![Biblioteca para el desarrollo rápido y sencillo de programas para MetaTrader (Parte XVI): Eventos de la colección de símbolos.](https://c.mql5.com/i/articles/overlay.png)
Biblioteca para el desarrollo rápido y sencillo de programas para MetaTrader (Parte XVI): Eventos de la colección de símbolos.
Contenido
- Clase de objeto básico para todos los objetos de la biblioteca
- Eventos de la colección de símbolos
- Mejorando la clase de eventos de cuenta
- Activando la clase de eventos de símbolo y la clase actualizada de la cuenta para el trabajo
- Simulando los eventos de símbolo y cuenta
- ¿Qué es lo próximo?
Antes, al crear un objeto de cuenta y la colección de cuentas en la parte 12, y posteriormente para monitorear los eventos de la cuenta actual en la parte 13 de la descripción de la biblioteca, definimos un tipo de objetos nuevo para la biblioteca, que enviaba sus eventos al objeto básico Engine.
Los principios de seguimiento de los eventos de la cuenta se diferencian de los principios de seguimiento de los eventos comerciales que analizamos a partir del artículo 4: mientras que los eventos comerciales se determinan e introducen en la colección de eventos comerciales para obtener acceso completo a cualquiera de los eventos sucedidos anteriormente, los eventos de cuenta funcionan en tiempo real, "aquí y ahora", un evento se determina y se envía mediante EventChartCustom() al gráfico con el programa, además de enviarse al objeto básico de la biblioteca. A continuación, podemos obtener en nuestro programa desde el objeto básico de la biblioteca acceso a la lista de eventos sucedidos simultáneamente y procesar estos. Así se organizan los eventos del objeto de cuenta.
Y es aquí cunado comprendemos que prácticamente cada uno de los objetos contiene un cierto número de propiedades que se repiten de un objeto a otro. Y que registramos cada una de estas propiedades una y otra vez en cada nuevo objeto al desarrollarlo.
Esto nos empuja a tomar una decisión unívoca: crear un objeto básico a partir del cual se heredarán todos los objetos de la biblioteca. Ahora son heredados del objeto básico CObject de la biblioteca estándar. Vamos a crear otro objeto heredero de CObject y heredaremos ya de él todos los objetos de nuestra biblioteca. De esta forma, todas las propiedades comunes para cada objeto se podrán escribir una vez en el objeto básico, y todos los objetos herederos recibirán dichas propiedades.
Sin embargo, lo más interesante es que ahora se podrá crear un objeto de evento y registrarlo en el objeto básico, y todos nuestros objetos de la biblioteca dispondrán de la posibilidad de enviar sus eventos al programa. Eso es precisamente lo que necesitamos en el concepto de la biblioteca, que los objetos puedan anunciar al programa por sí mismos sobre su estado, mientras que la biblioteca o programa, basándose en los mensajes de los objetos, pueda procesar posteriormente estos mensajes, y, o bien tomar decisiones (programa), o bien realizar las acciones pertinentes en cuanto al procesamiento de los eventos de los objetos (biblioteca). Por consiguiente, esto aumentará la interactividad de la propia biblioteca, simplificando enormemente el desarrollo de programas para el susuario final, dado que todas las acciones de procesamiento de eventos de cualquier objeto serán asumidas por la biblioteca.
La estructura del objeto de evento de los objetos repetirá los datos necesarios para el envío con la función EventChartCustom(): el identificador del evento, el parámetro long, el parámetro double y el parámetro string del evento. De esta forma, se simplificará para nosotros el envío de eventos al programa, dado que al registrarse un evento del objeto, todos los datos que se deben enviar al programa sobre el evento sucedido se rellenan de inmediato en la clase del objeto en el que ha sucedido el evento, y solo tendremos que obtenerlo y reenviarlo al programa para su posterior procesamiento.
Vamos a terminar con la teoría y pasar al desarrollo propiamente dicho. En primer lugar, creamos el objeto de evento, después el objeto básico, y finalmente, implementamos el seguimiento de los eventos de la colección de símbolos y corregimos la clase de eventos de cuenta de acuerdo con el concepto creado. No vamos a modificar los eventos comerciales, ya que tienen otra estructura completamente distinta, y este concepto no casa con ella; además, los eventos comerciales tienen un aspecto finalizado, funcionan y envían sus resultados al programa.
Clase de objeto básico para todos los objetos de la biblioteca
Bien. Creamos en el directorio de la biblioteca \MQL5\Include\DoEasy\Objects\ la nueva clase CBaseObj en el archivo BaseObj.mqh. El objeto básico de la clase debe ser el objeto básico de la biblioteca estándar CObject. La clase no será grande, por eso mostraremos su listado completo, analizándola después por miembros y métodos.
Una pequeña observación: para no tener que crear un nuevo archivo para la clase de eventos de objeto, vamos a escribir esta clase antes de la clase básica de los objetos en este mismo archivo://+------------------------------------------------------------------+ //| BaseObj.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include <Arrays\ArrayObj.mqh> #include "..\Services\DELib.mqh" //+------------------------------------------------------------------+ //| Base object event class for all library objects | //+------------------------------------------------------------------+ class CEventBaseObj : public CObject { private: long m_time; long m_chart_id; ushort m_event_id; long m_lparam; double m_dparam; string m_sparam; public: void Time(const long time) { this.m_time=time; } long Time(void) const { return this.m_time; } void ChartID(const long chart_id) { this.m_chart_id=chart_id; } long ChartID(void) const { return this.m_chart_id; } void ID(const ushort id) { this.m_event_id=id; } ushort ID(void) const { return this.m_event_id; } void LParam(const long lparam) { this.m_lparam=lparam; } long LParam(void) const { return this.m_lparam; } void DParam(const double dparam) { this.m_dparam=dparam; } double DParam(void) const { return this.m_dparam; } void SParam(const string sparam) { this.m_sparam=sparam; } string SParam(void) const { return this.m_sparam; } public: //--- Constructor CEventBaseObj(const ushort event_id,const long lparam,const double dparam,const string sparam) : m_chart_id(::ChartID()) { this.m_event_id=event_id; this.m_lparam=lparam; this.m_dparam=dparam; this.m_sparam=sparam; } //--- Comparison method to search for identical event objects virtual int Compare(const CObject *node,const int mode=0) const { const CEventBaseObj *compared=node; return ( this.ID()>compared.ID() ? 1 : this.ID()<compared.ID() ? -1 : this.LParam()>compared.LParam() ? 1 : this.LParam()<compared.LParam() ? -1 : this.DParam()>compared.DParam() ? 1 : this.DParam()<compared.DParam() ? -1 : this.SParam()>compared.SParam() ? 1 : this.SParam()<compared.SParam() ? -1 : 0 ); } }; //+------------------------------------------------------------------+ //| Base object class for all library objects | //+------------------------------------------------------------------+ class CBaseObj : public CObject { private: protected: CArrayObj m_list_events; // Object event list MqlTick m_tick; // Tick structure for receiving quote data double m_hash_sum; // Object data hash sum double m_hash_sum_prev; // Object data hash sum during the previous check int m_digits_currency; // Number of decimal places in an account currency int m_global_error; // Global error code long m_chart_id; // Control program chart ID bool m_is_event; // Object event flag int m_event_code; // Object event code string m_name; // Object name string m_folder_name; // Name of the folder storing CBaseObj descendant objects //--- Return time in milliseconds from MqlTick long TickTime(void) const { return #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ;} //--- return the flag of the event code presence in the event object bool IsPresentEventFlag(const int change_code) const { return (this.m_event_code & change_code)==change_code; } //--- Return the number of decimal places of the account currency int DigitsCurrency(void) const { return this.m_digits_currency; } //--- Returns the number of decimal places in the 'double' value int GetDigits(const double value) const; //--- Initialize the variables of (1) tracked, (2) controlled object data (implementation in the descendants) virtual void InitChangesParams(void); virtual void InitControlsParams(void); //--- (1) Check the object change, return the change code, (2) set the event type and fill in the list of events (implementation in the descendants) virtual int SetEventCode(void); virtual void SetTypeEvent(void); public: //--- Add the event object to the list bool EventAdd(const ushort event_id,const long lparam,const double dparam,const string sparam); //--- Return the occurred event flag to the object data bool IsEvent(void) const { return this.m_is_event; } //--- Return (1) the list of events, (2) the object event code and (3) the global error code CArrayObj *GetListEvents(void) { return &this.m_list_events; } int GetEventCode(void) const { return this.m_event_code; } int GetError(void) const { return this.m_global_error; } //--- Return the event object by its number in the list CEventBaseObj *GetEvent(const int shift=WRONG_VALUE,const bool check_out=true); //--- Return the number of object events int GetEventsTotal(void) const { return this.m_list_events.Total(); } //--- (1) Set and (2) return the chart ID of the control program void SetChartID(const long id) { this.m_chart_id=id; } long GetChartID(void) const { return this.m_chart_id; } //--- (1) Set the sub-folder name, (2) return the folder name for storing descendant object files void SetSubFolderName(const string name) { this.m_folder_name=DIRECTORY+name; } string GetFolderName(void) const { return this.m_folder_name; } //--- Return the object name string GetName(void) const { return this.m_name; } //--- Update the object data (implementation in the descendants) virtual void Refresh(void); //--- Constructor CBaseObj(); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CBaseObj::CBaseObj() : m_global_error(ERR_SUCCESS), m_hash_sum(0),m_hash_sum_prev(0), m_is_event(false),m_event_code(0), m_chart_id(::ChartID()), m_folder_name(DIRECTORY), m_name("") { ::ZeroMemory(this.m_tick); this.m_digits_currency=(#ifdef __MQL5__ (int)::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2 #endif); this.m_list_events.Clear(); this.m_list_events.Sort(); } //+------------------------------------------------------------------+ //| Add the event object to the list | //+------------------------------------------------------------------+ bool CBaseObj::EventAdd(const ushort event_id,const long lparam,const double dparam,const string sparam) { CEventBaseObj *event=new CEventBaseObj(event_id,lparam,dparam,sparam); if(event==NULL) return false; this.m_list_events.Sort(); if(this.m_list_events.Search(event)>WRONG_VALUE) { delete event; return false; } return this.m_list_events.Add(event); } //+------------------------------------------------------------------+ //| Return the object event by its index in the list | //+------------------------------------------------------------------+ CEventBaseObj *CBaseObj::GetEvent(const int shift=WRONG_VALUE,const bool check_out=true) { int total=this.m_list_events.Total(); if(total==0 || (!check_out && shift>total-1)) return NULL; int index=(shift<=0 ? total-1 : shift>total-1 ? 0 : total-shift-1); CEventBaseObj *event=this.m_list_events.At(index); return(event!=NULL ? event : NULL); } //+------------------------------------------------------------------+ //| Return the number of decimal places in the 'double' value | //+------------------------------------------------------------------+ int CBaseObj::GetDigits(const double value) const { string val_str=(string)value; int len=::StringLen(val_str); int n=len-::StringFind(val_str,".",0)-1; if(::StringSubstr(val_str,len-1,1)=="0") n--; return n; } //+------------------------------------------------------------------+
Vamos a analizar la clase de los eventos del objeto básico.
En la clase de los eventos del objeto básico, en la sección privada, hemos declarado las variables de miembro de clase para guardar todas las propiedades del evento:
private: long m_time; long m_chart_id; ushort m_event_id; long m_lparam; double m_dparam; string m_sparam;
La hora del evento, el identificador del gráfico al que se envía el evento, el identificador del evento, el valor long, el valor double y el valor string del evento, que se transmitirán al gráfico al programa de control.
Transmitimos de inmediato al constructor de clase los valores para la mayoría de estas variables:
//--- Constructor CEventBaseObj(const ushort event_id,const long lparam,const double dparam,const string sparam) : m_chart_id(::ChartID()) { this.m_event_id=event_id; this.m_lparam=lparam; this.m_dparam=dparam; this.m_sparam=sparam; }
donde se les asignan los valores transmitidos.
También en la lista de inicialización de la clase, se le asigna a la variable de identificador el valor de la ID del gráfico actual.
Método de comparación de dos clases de evento de objetos:
//--- Comparison method to search for identical event objects virtual int Compare(const CObject *node,const int mode=0) const { const CEventBaseObj *compared=node; return ( this.ID()>compared.ID() ? 1 : this.ID()<compared.ID() ? -1 : this.LParam()>compared.LParam() ? 1 : this.LParam()<compared.LParam() ? -1 : this.DParam()>compared.DParam() ? 1 : this.DParam()<compared.DParam() ? -1 : this.SParam()>compared.SParam() ? 1 : this.SParam()<compared.SParam() ? -1 : 0 ); }
realiza una comparación elemento por elemento de todos los campos de las dos clases: la actual y la transmitida al método según el puntero. Si todos los campos son iguales entre sí, el método retornará 0, lo cual resulta imprescindible para realizar la búsqueda del mismo objeto exacto en la lista dinámica de punteros de la biblioteca estándar, ya que estos objetos se guardan en la lista CArrayObj, y para su método Search(), pensado para la búsqueda de objetos idénticos en la lista:
//+------------------------------------------------------------------+ //| Search of position of element in a sorted array | //+------------------------------------------------------------------+ int CArrayObj::Search(const CObject *element) const { int pos; //--- check if(m_data_total==0 || !CheckPointer(element) || m_sort_mode==-1) return(-1); //--- search pos=QuickSearch(element); if(m_data[pos].Compare(element,m_sort_mode)==0) return(pos); //--- not found return(-1); } //+------------------------------------------------------------------+
es necesario que el objeto tenga el método virtual Compare(), que retorna 0 si conciden todas las propiedades de dos objetos)
En la sección pública de la clase, declaramos los métodos para establecer y retornar todas las propiedades de un objeto:
public: void Time(const long time) { this.m_time=time; } long Time(void) const { return this.m_time; } void ChartID(const long chart_id) { this.m_chart_id=chart_id; } long ChartID(void) const { return this.m_chart_id; } void ID(const ushort id) { this.m_event_id=id; } ushort ID(void) const { return this.m_event_id; } void LParam(const long lparam) { this.m_lparam=lparam; } long LParam(void) const { return this.m_lparam; } void DParam(const double dparam) { this.m_dparam=dparam; } double DParam(void) const { return this.m_dparam; } void SParam(const string sparam) { this.m_sparam=sparam; } string SParam(void) const { return this.m_sparam; }
Aquí todo esta claro, así que no haremos mayores aclaraciones. Esta es la clase completa del evento de objeto.
Vamos a analizar la clase del objeto básico para todos los objetos de la biblioteca.
En la sección protegida de la clase, hemos declarado las variables de miembro de clase que ya conocemos de objetos anteriores:
protected: CArrayObj m_list_events; // Object event list MqlTick m_tick; // Tick structure for receiving quote data double m_hash_sum; // Object data hash sum double m_hash_sum_prev; // Object data hash sum during the previous check int m_digits_currency; // Number of decimal places in an account currency int m_global_error; // Global error code long m_chart_id; // Control program chart ID bool m_is_event; // Object event flag int m_event_code; // Object event code string m_name; // Object name string m_folder_name; // Name of the folder storing CBaseObj descendant objects
- La lista de eventos de objeto m_list_events, en ella ubicaremos los objetos de clase de evento que ya hemos analizado. Ya que en un objeto se pueden dar varios eventos a la vez, vamos a necesitar determinarlos y colocarlos en esta lista. A continuación, podemos extraer del objeto principal de la biblioteca CEngine la lista con todos los eventos y procesar estos.
- La estructura de ticks m_tick sirve para obtener los precios y la hora de un evento.
- La suma hash m_hash_sum es necesaria para determinar los cambios sucedidos en las propiedades de un objeto.
El cambio en las propiedades del objeto se determina comparando la suma actual y la previa ( m_hash_sum_prev). - El número de dígitos tras la coma para la divisa de la cuenta m_digits_currency es imprescindible para mostrar correctamente la información sobre ciertos eventos relacionados con el cambio de las magnitudes monetarias.
- Anotamos en el código de error global m_global_error el número del error obtenido al retornar erróneamente alguna de las funciones. Este código se transmite al programa que realiza la llamada para su posterior procesamiento.
- El identificador de tráfico del programa de control m_chart_id sirve para indicar a qué tráfico se refiere el evento sucedido en el objeto.
- La bandera de evento del objeto m_is_event es necesaria para indicar al programa que ha sucedido un evento en el objeto solicitado.
- El código de evento del objeto m_event_code guarda las banderas de todos los eventos sucedidos simultáneamente. Podemos determinar la lista de eventos de objeto sucedidos de forma simultánea en función de la presencia de estas banderas.
- La denominación del objeto m_name es necesaria para indicar al programa ciertas propiedades de texto del objeto del que se obtendrán los eventos. Por ejemplo, para la cuenta, se tratará del número de cuenta+el nombre del cliente+la denominación del servidor, y para el símbolo, la denominación del símbolo.
- El nombre de la carpeta para guardar los archivos de los objetos m_folder_name es necesario para almacenar el objeto en un archivo: aquí se guarda el nombre de la subcarpeta en el que se almacenan los archivos de los objetos de un mismo tipo.
El directorio básico para las subcarpetas es el directorio de ubicación de los archivos comunes de todos los terminales de cliente+el nombre de la carpeta de la biblioteca: "DoEasy\\". Ya analizamos el guardado de archivos al crear la colección de cuentas en la parte 12 de la descripción de la biblioteca.
Todas estas propiedades ya las creamos en los objetos de la biblioteca, además de analizarlas en diferentes partes de la descripción de la biblioteca que se corresponden con los objetos estudiados. Ahora, las hemos ubicado en una sola clase, en el objeto básico de todos los objetos de la biblioteca CBaseObj, quitando al mismo tiempo de las clases de los objetos herederos la determinación de estos miembros de clase (para no tener que describir los cambios aquí, el lector podrá mirar los cambios en los archivos adjuntos).
Vamos a echar un vistazo a los métodos ubicados en la sección privada de la clase:
//--- Return time in milliseconds from MqlTick long TickTime(void) const { return #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ;} //--- return the flag of the event code presence in the event object bool IsPresentEventFlag(const int change_code) const { return (this.m_event_code & change_code)==change_code; } //--- Return the number of decimal places of the account currency int DigitsCurrency(void) const { return this.m_digits_currency; } //--- Returns the number of decimal places in the 'double' value int GetDigits(const double value) const; //--- Initialize the variables of (1) tracked, (2) controlled object data (implementation in the descendants) virtual void InitChangesParams(void); virtual void InitControlsParams(void); //--- (1) Check the object change, return the change code, (2) set the event type and fill in the list of events (implementation in the descendants) virtual int SetEventCode(void); virtual void SetTypeEvent(void);
- El método TickTime() retorna la hora de un evento en milisegundos. Para MQL4, debido a la ausencia de milisegundos en la estructura, se retornará la hora en segundos * 1000
- El método IsPresentEventFlag() retorna la existencia de código de un determinado evento en el valor de la variable m_event_code.
- El método DigitsCurrency() retorna el número de dígitos tras la coma en el valor de la divisa de la cuenta de la variable m_digits_currency.
- El método GetDigits() calcula y retorna el número de dígitos tras la coma en el valor double transmitido a él.
- El método virtual InitChangesParams() inicializa los parámetros de todas las propiedades del objeto cambiadas.
- El método virtual InitControlsParams() inicializa los parámetros de las propiedades del objeto monitoreadas.
- El método virtual SetEventCode() comprueba el cambio de las propiedades del objeto y retorna el código de los cambios acaecidos.
- El método virtual SetTypeEvent() establece el tipo de evento sucedido usando como base el código del evento y ubica todos los eventos en la lista de eventos del objeto.
Ya hemos desarrollado todos estos métodos en los artículos anteriores, por lo que no vamos a volver a describirlos aquí. Solo diremos que ninguno de los métodos virtuales ejecuta nada aquí, por lo que será necesario implementarlos en las clases herederas del objeto básico.
En la sección pública de la clase, declaramos los métodos:
public: //--- Add the event object to the list bool EventAdd(const ushort event_id,const long lparam,const double dparam,const string sparam); //--- Return the occurred event flag to the object data bool IsEvent(void) const { return this.m_is_event; } //--- Return (1) the list of events, (2) the object event code and (3) the global error code CArrayObj *GetListEvents(void) { return &this.m_list_events; } int GetEventCode(void) const { return this.m_event_code; } int GetError(void) const { return this.m_global_error; } //--- Return the event object by its number in the list CEventBaseObj *GetEvent(const int shift=WRONG_VALUE,const bool check_out=true); //--- Return the number of object events int GetEventsTotal(void) const { return this.m_list_events.Total(); } //--- (1) Set and (2) return the chart ID of the control program void SetChartID(const long id) { this.m_chart_id=id; } long GetChartID(void) const { return this.m_chart_id; } //--- (1) Set the sub-folder name, (2) return the folder name for storing descendant object files void SetSubFolderName(const string name) { this.m_folder_name=DIRECTORY+name; } string GetFolderName(void) const { return this.m_folder_name; } //--- Return the object name string GetName(void) const { return this.m_name; } //--- Update the object data (implementation in the descendants) virtual void Refresh(void);
Asignamos los valores iniciales a las variables de miembro de clase en la lista de inicialización del constructor de clase:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CBaseObj::CBaseObj() : m_global_error(ERR_SUCCESS), m_hash_sum(0),m_hash_sum_prev(0), m_is_event(false),m_event_code(0), m_chart_id(::ChartID()), m_folder_name(DIRECTORY), m_name("") { ::ZeroMemory(this.m_tick); this.m_digits_currency=(#ifdef __MQL5__ (int)::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2 #endif); this.m_list_events.Clear(); this.m_list_events.Sort(); } //+------------------------------------------------------------------+
A continuación, se resetea la estructura del tick, se asigna el valor del número de dígitos tras la coma para la divisa de la cuenta, se limpia la lista de eventos y se establece la bandera de lista clasificada para la lista de eventos de objeto.
Método de adición de eventos a la lista:
//+------------------------------------------------------------------+ //| Add the event object to the list | //+------------------------------------------------------------------+ bool CBaseObj::EventAdd(const ushort event_id,const long lparam,const double dparam,const string sparam) { CEventBaseObj *event=new CEventBaseObj(event_id,lparam,dparam,sparam); if(event==NULL) return false; this.m_list_events.Sort(); if(this.m_list_events.Search(event)>WRONG_VALUE) { delete event; return false; } return this.m_list_events.Add(event); } //+------------------------------------------------------------------+
Transmitimos al método el identificador del evento y los valores long, double y string de las porpiedades del evento. A continuación, creamos un nuevo evento con estos parámetros. Si en la lista existe exactamente el mismo evento, el objeto de evento se elimina y el método retorna false, de lo contrario, el método retorna el resultado de la adición del objeto de evento a la lista.
Método que retorna el objeto de evento según su índice en la lista:
//+------------------------------------------------------------------+ //| Return the object event by its index in the list | //+------------------------------------------------------------------+ CEventBaseObj *CBaseObj::GetEvent(const int shift=WRONG_VALUE,const bool check_out=true) { int total=this.m_list_events.Total(); if(total==0 || (!check_out && shift>total-1)) return NULL; int index=(shift<=0 ? total-1 : shift>total-1 ? 0 : total-shift-1); CEventBaseObj *event=this.m_list_events.At(index); return(event!=NULL ? event : NULL); } //+------------------------------------------------------------------+
Ya hemos visto este método con anterioridad. Aquí solo se ha añadido la bandera de necesidad de comprobación y corrección del índice cuando su valor se sale de los límites de la lista. Por defecto, al método se le transmite el índice -1 y la comprobación de la salida del índice fuera de los límites de la lista. En este caso, el método retornará el último objeto de evento de la lista. Para obtener un objeto según su índice, debemos transmitir al método el índice requerido y la bandera de control de salida fuera de la lista = false. En este caso, se retornará el objeto (si el índice se encuentra dentro de la lista), o bien NULL, si el índice se encuentra fuera de la misma.
El método que retorna el número de dígitos tras la coma en un valor double, también lo hemos analizado anteriormente:
//+------------------------------------------------------------------+ //| Return the number of decimal places in the 'double' value | //+------------------------------------------------------------------+ int CBaseObj::GetDigits(const double value) const { string val_str=(string)value; int len=::StringLen(val_str); int n=len-::StringFind(val_str,".",0)-1; if(::StringSubstr(val_str,len-1,1)=="0") n--; return n; } //+------------------------------------------------------------------+
El nuevo objeto básico está listo.
Ahora, solo necesitamos sustituir en cada uno de los objetos básicos de la biblioteca la clase básica CObject por CBaseObj. En nuestro caso, dichos objetos serán:
el objeto de clase CAccount:
//+------------------------------------------------------------------+ //| Account class | //+------------------------------------------------------------------+ class CAccount : public CBaseObj {
el objeto de clase CSymbol:
//+------------------------------------------------------------------+ //| Abstract symbol class | //+------------------------------------------------------------------+ class CSymbol : public CBaseObj {
También asignaremos a las clases de colección las propiedades generales de los objetos:
colección de eventos comerciales:
//+------------------------------------------------------------------+ //| Collection of account trading events | //+------------------------------------------------------------------+ class CEventsCollection : public CBaseObj {
colección de cuentas:
//+------------------------------------------------------------------+ //| Account collection | //+------------------------------------------------------------------+ class CAccountsCollection : public CBaseObj {
colección de símbolos:
//+------------------------------------------------------------------+ //| Symbol collection | //+------------------------------------------------------------------+ class CSymbolsCollection : public CBaseObj {
Ahora, todos los objetos creados sobre la base de CBaseObj tienen el mismo conjunto de propiedades, y al crear nuevos objetos, no será necesario escribir en cada objeto los datos referentes a las propiedades. Además, ahora será posible añadir las propiedades que queramos, resultando estas iguales para todos los objetos creados usando como base este objeto básico. Y lo que es más interesante: cada uno de estos objetos dispone ahora de una herramienta para trabajar con eventos. Y el evento de cada uno de los objetos tiene el mismo conjunto de parámetros que la función para el envío de eventos al gráfico del programa EventChartCustom(). De esta forma, hemos simplificado sustancialmente el posterior desarrollo de nuevos objetos y la mejora de los ya preparados.
Ahora, ya podemos comenzar a crear el evento de colección de símbolos.
Eventos de la colección de símbolos
Como siempre, comenzamos definiendo las constantes y enumeraciones. Abrimos el archivo Defines.mqh y le añadimos los datos necesarios para monitorear los eventos de símbolo.
Dado que para trabajar con los símbolos es necesario que estén presentes en la ventana de "Observación de mercado", y su número en ella es limitado,
añadimos a los parámetros de los símbolos una línea con una macrosustitución que indica el número máximo posible de símbolos que se encuentran simultáneamente en la ventana de "Observación de mercado":
//--- Symbol parameters #define CLR_DEFAULT (0xFF000000) // Default color #define SYMBOLS_COMMON_TOTAL (1000) // Total number of working symbols
Trasladamos del apartado de datos para el trabajo con los símbolos la enumeración de los modos de trabajo con los símbolos
//+------------------------------------------------------------------+ //| Data for working with symbols | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Modes of working with symbols | //+------------------------------------------------------------------+ enum ENUM_SYMBOLS_MODE { SYMBOLS_MODE_CURRENT, // Work with the current symbol only SYMBOLS_MODE_DEFINES, // Work with the specified symbol list SYMBOLS_MODE_MARKET_WATCH, // Work with the Market Watch window symbols SYMBOLS_MODE_ALL // Work with the full symbol list }; //+------------------------------------------------------------------+
en el archivo Datas.mqh:
//+------------------------------------------------------------------+ //| Datas.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" //+------------------------------------------------------------------+ //| Enumerations | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Modes of working with symbols | //+------------------------------------------------------------------+ enum ENUM_SYMBOLS_MODE { SYMBOLS_MODE_CURRENT, // Work with the current symbol only SYMBOLS_MODE_DEFINES, // Work with the specified symbol list SYMBOLS_MODE_MARKET_WATCH, // Work with the Market Watch window symbols SYMBOLS_MODE_ALL // Work with the full symbol list }; //+------------------------------------------------------------------+ //| Data sets | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Major Forex symbols | //+------------------------------------------------------------------+ string DataSymbolsFXMajors[]= {
El motivo de la existencia de esta solución es que estos datos son necesarios no solo para la biblioteca, sino también para los programas que funcionan usando como base la biblioteca. Y esta enumeración se relaciona con los datos generales del programa, más que con los de la biblioteca. Por ejemplo, deberemos usarlos junto con muchas otras enumeraciones como parámetros de entrada de los programas, y esto significa que también tendremos que traducirlo al lenguaje de comunicación necesario (organizaremos este proceso más tarde). Por eso, vamos a dejarlo en Datas.mqh.
En lugar de la enumeración trasladada desde Defines.mqh, añadimos una enumeración con la lista de las banderas de los eventos de símbolo y la enumeración con la lista de posibles eventos de símbolo:
//+------------------------------------------------------------------+ //| Data for working with symbols | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| List of symbol event flags | //+------------------------------------------------------------------+ enum ENUM_SYMBOL_EVENT_FLAGS { SYMBOL_EVENT_FLAG_NO_EVENT = 0, // No event SYMBOL_EVENT_FLAG_TRADE_MODE = 1, // Change order execution permissions SYMBOL_EVENT_FLAG_SESSION_DEALS = 2, // Change the number of deals in the current session SYMBOL_EVENT_FLAG_SESSION_BUY_ORDERS = 4, // Change the total number of the current buy orders SYMBOL_EVENT_FLAG_SESSION_SELL_ORDERS = 8, // Change the total number of the current sell orders SYMBOL_EVENT_FLAG_VOLUME = 16, // Change in the last deal volume exceeds the specified value in +/- SYMBOL_EVENT_FLAG_VOLUME_HIGH_DAY = 32, // Change of the maximum volume per day exceeds the specified value in +/- SYMBOL_EVENT_FLAG_VOLUME_LOW_DAY = 64, // Change of the minimum volume per day exceeds the specified value in +/- SYMBOL_EVENT_FLAG_SPREAD = 128, // Change of a spread exceeds the specified change value in +/- SYMBOL_EVENT_FLAG_STOPLEVEL = 256, // Change of a Stop order level exceeds the specified value in +/- SYMBOL_EVENT_FLAG_FREEZELEVEL = 512, // Change of the freeze level exceeds the specified value in +/- SYMBOL_EVENT_FLAG_BID_LAST = 1024, // Change of the Bid or Last price exceeds the specified value in +/- SYMBOL_EVENT_FLAG_BID_LAST_HIGH = 2048, // Change of the maximum Bid or Last price per day exceeds the specified value in +/- SYMBOL_EVENT_FLAG_BID_LAST_LOW = 4096, // Change of the minimum Bid or Last price per day exceeds the specified value in +/- SYMBOL_EVENT_FLAG_ASK = 8192, // Change of the Ask price exceeds the specified value in +/- SYMBOL_EVENT_FLAG_ASK_HIGH = 16384, // Change of the maximum Ask price per day exceeds the specified value in +/- SYMBOL_EVENT_FLAG_ASK_LOW = 32768, // Change of the minimum Ask price per day exceeds the specified value in +/- SYMBOL_EVENT_FLAG_VOLUME_REAL_DAY = 65536, // Change of the real volume per day exceeds the specified value in +/- SYMBOL_EVENT_FLAG_VOLUME_HIGH_REAL_DAY = 131072, // Change of the maximum real volume per day exceeds the specified value in +/- SYMBOL_EVENT_FLAG_VOLUME_LOW_REAL_DAY = 262144, // Change of the minimum real volume per day exceeds the specified value in +/- SYMBOL_EVENT_FLAG_OPTION_STRIKE = 524288, // Change of the strike price exceeds the specified value in +/- SYMBOL_EVENT_FLAG_VOLUME_LIMIT = 1048576, // Change of the maximum available total position volume and pending orders in one direction SYMBOL_EVENT_FLAG_SWAP_LONG = 2097152, // Change swap long SYMBOL_EVENT_FLAG_SWAP_SHORT = 4194304, // Change swap short SYMBOL_EVENT_FLAG_SESSION_VOLUME = 8388608, // Change of the total volume of deals in the current session exceeds the specified value in +/- SYMBOL_EVENT_FLAG_SESSION_TURNOVER = 16777216, // Change of the total turnover in the current session exceeds the specified value in +/- SYMBOL_EVENT_FLAG_SESSION_INTEREST = 33554432, // Change of the total volume of open positions in the current session exceeds the specified value in +/- SYMBOL_EVENT_FLAG_SESSION_BUY_ORD_VOLUME = 67108864, // Change of the total volume of buy orders exceeds the specified value in +/- SYMBOL_EVENT_FLAG_SESSION_SELL_ORD_VOLUME = 134217728, // Change of the total volume of sell orders exceeds the specified value in +/- SYMBOL_EVENT_FLAG_SESSION_OPEN = 268435456, // Change of the session open price exceeds the specified value in +/- SYMBOL_EVENT_FLAG_SESSION_CLOSE = 536870912, // Change of the session close price exceeds the specified value in +/- SYMBOL_EVENT_FLAG_SESSION_AW = 1073741824 // Change of the average weighted session price exceeds the specified value in +/- }; //+------------------------------------------------------------------+ //| List of possible symbol events | //+------------------------------------------------------------------+ enum ENUM_SYMBOL_EVENT { SYMBOL_EVENT_NO_EVENT = ACCOUNT_EVENTS_NEXT_CODE, // No event SYMBOL_EVENT_MW_ADD, // Adding a symbol to the Market Watch window SYMBOL_EVENT_MW_DEL, // Removing a symbol from the Market Watch window SYMBOL_EVENT_MW_SORT, // Sorting symbols in the Market Watch window SYMBOL_EVENT_TRADE_DISABLE, // Disable order execution SYMBOL_EVENT_TRADE_LONGONLY, // Allow buy only SYMBOL_EVENT_TRADE_SHORTONLY, // Allow sell only SYMBOL_EVENT_TRADE_CLOSEONLY, // Enable close only SYMBOL_EVENT_TRADE_FULL, // No trading limitations SYMBOL_EVENT_SESSION_DEALS_INC, // The increase in the number of deals in the current session exceeds the specified value SYMBOL_EVENT_SESSION_DEALS_DEC, // The decrease in the number of deals in the current session exceeds the specified value SYMBOL_EVENT_SESSION_BUY_ORDERS_INC, // The increase in the total number of buy orders currently exceeds the specified value SYMBOL_EVENT_SESSION_BUY_ORDERS_DEC, // The decrease in the total number of buy orders currently exceeds the specified value SYMBOL_EVENT_SESSION_SELL_ORDERS_INC, // The increase in the total number of sell orders currently exceeds the specified value SYMBOL_EVENT_SESSION_SELL_ORDERS_DEC, // The decrease in the total number of sell orders currently exceeds the specified value SYMBOL_EVENT_VOLUME_INC, // Volume increase in the last deal exceeds the specified value SYMBOL_EVENT_VOLUME_DEC, // Volume decrease in the last deal exceeds the specified value SYMBOL_EVENT_VOLUME_HIGH_DAY_INC, // The increase in the maximum volume per day exceeds the specified value SYMBOL_EVENT_VOLUME_HIGH_DAY_DEC, // The decrease in the maximum volume per day exceeds the specified value SYMBOL_EVENT_VOLUME_LOW_DAY_INC, // The increase in the minimum volume per day exceeds the specified value SYMBOL_EVENT_VOLUME_LOW_DAY_DEC, // The decrease in the minimum volume per day exceeds the specified value SYMBOL_EVENT_SPREAD_INC, // The increase in a spread exceeds the specified change SYMBOL_EVENT_SPREAD_DEC, // The decrease in a spread exceeds the specified change SYMBOL_EVENT_STOPLEVEL_INC, // The increase of a Stop order level exceeds the specified value SYMBOL_EVENT_STOPLEVEL_DEC, // The decrease of a Stop order level exceeds the specified value SYMBOL_EVENT_FREEZELEVEL_INC, // The increase in the freeze level exceeds the specified value SYMBOL_EVENT_FREEZELEVEL_DEC, // The decrease in the freeze level exceeds the specified value SYMBOL_EVENT_BID_LAST_INC, // The increase in the Bid or Last price exceeds the specified value SYMBOL_EVENT_BID_LAST_DEC, // The decrease in the Bid or Last price exceeds the specified value SYMBOL_EVENT_BID_LAST_HIGH_INC, // The increase in the maximum Bid or Last price per day exceeds the specified value SYMBOL_EVENT_BID_LAST_HIGH_DEC, // The decrease in the maximum Bid or Last price per day exceeds the specified value relative to the specified price SYMBOL_EVENT_BID_LAST_LOW_INC, // The increase in the minimum Bid or Last price per day exceeds the specified value relative to the specified price SYMBOL_EVENT_BID_LAST_LOW_DEC, // The decrease in the minimum Bid or Last price per day exceeds the specified value SYMBOL_EVENT_ASK_INC, // The increase in the Ask price exceeds the specified value SYMBOL_EVENT_ASK_DEC, // The decrease in the Ask price exceeds the specified value SYMBOL_EVENT_ASK_HIGH_INC, // The increase in the maximum Ask price per day exceeds the specified value SYMBOL_EVENT_ASK_HIGH_DEC, // The decrease in the maximum Ask price per day exceeds the specified value SYMBOL_EVENT_ASK_LOW_INC, // The increase in the minimum Ask price per day exceeds the specified value SYMBOL_EVENT_ASK_LOW_DEC, // The decrease in the minimum Ask price per day exceeds the specified value SYMBOL_EVENT_VOLUME_REAL_DAY_INC, // The increase in the real volume per day exceeds the specified value SYMBOL_EVENT_VOLUME_REAL_DAY_DEC, // The decrease in the real volume per day exceeds the specified value SYMBOL_EVENT_VOLUME_HIGH_REAL_DAY_INC, // The increase in the maximum real volume per day exceeds the specified value SYMBOL_EVENT_VOLUME_HIGH_REAL_DAY_DEC, // The decrease in the maximum real volume per day exceeds the specified value SYMBOL_EVENT_VOLUME_LOW_REAL_DAY_INC, // The increase in the minimum real volume per day exceeds the specified value SYMBOL_EVENT_VOLUME_LOW_REAL_DAY_DEC, // The decrease in the minimum real volume per day exceeds the specified value SYMBOL_EVENT_OPTION_STRIKE_INC, // The increase in the strike price exceeds the specified value SYMBOL_EVENT_OPTION_STRIKE_DEC, // The decrease in the strike price exceeds the specified value SYMBOL_EVENT_VOLUME_LIMIT_INC, // The increase in the maximum available total position volume and pending orders in one direction SYMBOL_EVENT_VOLUME_LIMIT_DEC, // The decrease in the maximum available total position volume and pending orders in one direction SYMBOL_EVENT_SWAP_LONG_INC, // The increase in the swap long SYMBOL_EVENT_SWAP_LONG_DEC, // The decrease in the swap long SYMBOL_EVENT_SWAP_SHORT_INC, // The increase in the swap short SYMBOL_EVENT_SWAP_SHORT_DEC, // The decrease in the swap short SYMBOL_EVENT_SESSION_VOLUME_INC, // The increase in the total volume of deals in the current session exceeds the specified value SYMBOL_EVENT_SESSION_VOLUME_DEC, // The decrease in the total volume of deals in the current session exceeds the specified value SYMBOL_EVENT_SESSION_TURNOVER_INC, // The increase in the total turnover in the current session exceeds the specified value SYMBOL_EVENT_SESSION_TURNOVER_DEC, // The decrease in the total turnover in the current session exceeds the specified value SYMBOL_EVENT_SESSION_INTEREST_INC, // The increase in the total volume of open positions in the current session exceeds the specified value SYMBOL_EVENT_SESSION_INTEREST_DEC, // The decrease in the total volume of open positions in the current session exceeds the specified value SYMBOL_EVENT_SESSION_BUY_ORD_VOLUME_INC, // The increase in the total volume of buy orders exceeds the specified value SYMBOL_EVENT_SESSION_BUY_ORD_VOLUME_DEC, // The decrease in the total volume of buy orders exceeds the specified value SYMBOL_EVENT_SESSION_SELL_ORD_VOLUME_INC, // The increase in the total volume of sell orders exceeds the specified value SYMBOL_EVENT_SESSION_SELL_ORD_VOLUME_DEC, // The decrease in the total volume of sell orders exceeds the specified value SYMBOL_EVENT_SESSION_OPEN_INC, // The increase in the session open price exceeds the specified value relative to the specified price SYMBOL_EVENT_SESSION_OPEN_DEC, // The decrease in the session open price exceeds the specified value relative to the specified price SYMBOL_EVENT_SESSION_CLOSE_INC, // The increase in the session close price exceeds the specified value relative to the specified price SYMBOL_EVENT_SESSION_CLOSE_DEC, // The decrease in the session close price exceeds the specified value relative to the specified price SYMBOL_EVENT_SESSION_AW_INC, // The increase in the average weighted session price exceeds the specified value SYMBOL_EVENT_SESSION_AW_DEC, // The decrease in the average weighted session price exceeds the specified value }; #define SYMBOL_EVENTS_NEXT_CODE (SYMBOL_EVENT_SESSION_AW_DEC+1) // The code of the next event after the last symbol event code //+------------------------------------------------------------------+
Aquí todo sucede igual que en las enumeraciones de las banderas y los posibles eventos de la cuenta y los eventos comerciales. Ya hemos analizado las banderas de eventos y los identificadores de eventos en la cuarta parte de la descripción de la biblioteca.
Para clasificar los símbolos según su ubicación en la ventana de "Observación de mercado", vamos añadir otra propiedad de tipo de entero del símbolo:
//+------------------------------------------------------------------+ //| Symbol integer properties | //+------------------------------------------------------------------+ enum ENUM_SYMBOL_PROP_INTEGER { SYMBOL_PROP_STATUS = 0, // Symbol status SYMBOL_PROP_INDEX_MW, // Symbol index in the Market Watch window SYMBOL_PROP_CUSTOM, // Custom symbol flag SYMBOL_PROP_CHART_MODE, // The price type used for generating bars – Bid or Last (from the ENUM_SYMBOL_CHART_MODE enumeration) SYMBOL_PROP_EXIST, // Flag indicating that the symbol under this name exists SYMBOL_PROP_SELECT, // The indication that the symbol is selected in Market Watch SYMBOL_PROP_VISIBLE, // The indication that the symbol is displayed in Market Watch SYMBOL_PROP_SESSION_DEALS, // The number of deals in the current session SYMBOL_PROP_SESSION_BUY_ORDERS, // The total number of Buy orders at the moment SYMBOL_PROP_SESSION_SELL_ORDERS, // The total number of Sell orders at the moment SYMBOL_PROP_VOLUME, // Last deal volume SYMBOL_PROP_VOLUMEHIGH, // Maximum volume within a day SYMBOL_PROP_VOLUMELOW, // Minimum volume within a day SYMBOL_PROP_TIME, // Latest quote time SYMBOL_PROP_DIGITS, // Number of decimal places SYMBOL_PROP_DIGITS_LOTS, // Number of decimal places for a lot SYMBOL_PROP_SPREAD, // Spread in points SYMBOL_PROP_SPREAD_FLOAT, // Floating spread flag SYMBOL_PROP_TICKS_BOOKDEPTH, // Maximum number of orders displayed in the Depth of Market SYMBOL_PROP_TRADE_CALC_MODE, // Contract price calculation method (from the ENUM_SYMBOL_CALC_MODE enumeration) SYMBOL_PROP_TRADE_MODE, // Order execution type (from the ENUM_SYMBOL_TRADE_MODE enumeration) SYMBOL_PROP_START_TIME, // Symbol trading start date (usually used for futures) SYMBOL_PROP_EXPIRATION_TIME, // Symbol trading end date (usually used for futures) SYMBOL_PROP_TRADE_STOPS_LEVEL, // Minimum distance in points from the current close price for setting Stop orders SYMBOL_PROP_TRADE_FREEZE_LEVEL, // Freeze distance for trading operations (in points) SYMBOL_PROP_TRADE_EXEMODE, // Deal execution mode (from the ENUM_SYMBOL_TRADE_EXECUTION enumeration) SYMBOL_PROP_SWAP_MODE, // Swap calculation model (from the ENUM_SYMBOL_SWAP_MODE enumeration) SYMBOL_PROP_SWAP_ROLLOVER3DAYS, // Triple-day swap (from the ENUM_DAY_OF_WEEK enumeration) SYMBOL_PROP_MARGIN_HEDGED_USE_LEG, // Calculating hedging margin using the larger leg (Buy or Sell) SYMBOL_PROP_EXPIRATION_MODE, // Flags of allowed order expiration modes SYMBOL_PROP_FILLING_MODE, // Flags of allowed order filling modes SYMBOL_PROP_ORDER_MODE, // Flags of allowed order types SYMBOL_PROP_ORDER_GTC_MODE, // Expiration of Stop Loss and Take Profit orders if SYMBOL_EXPIRATION_MODE=SYMBOL_EXPIRATION_GTC (from the ENUM_SYMBOL_ORDER_GTC_MODE enumeration) SYMBOL_PROP_OPTION_MODE, // Option type (from the ENUM_SYMBOL_OPTION_MODE enumeration) SYMBOL_PROP_OPTION_RIGHT, // Option right (Call/Put) (from the ENUM_SYMBOL_OPTION_RIGHT enumeration) //--- skipped property SYMBOL_PROP_BACKGROUND_COLOR // The color of the background used for the symbol in Market Watch }; #define SYMBOL_PROP_INTEGER_TOTAL (36) // Total number of integer properties #define SYMBOL_PROP_INTEGER_SKIP (1) // Number of symbol integer properties not used in sorting //+------------------------------------------------------------------+
Y dado que hemos añadido una nueva propiedad, deberemos aumentar el número total de propiedades de tipo entero a 36 , en lugar de las anteriores 35.
Finalmente, añadimos a la lista de posibles criterios de clasificación de los símbolos esta nueva propiedad:
//+------------------------------------------------------------------+ //| Possible symbol sorting criteria | //+------------------------------------------------------------------+ #define FIRST_SYM_DBL_PROP (SYMBOL_PROP_INTEGER_TOTAL-SYMBOL_PROP_INTEGER_SKIP) #define FIRST_SYM_STR_PROP (SYMBOL_PROP_INTEGER_TOTAL-SYMBOL_PROP_INTEGER_SKIP+SYMBOL_PROP_DOUBLE_TOTAL-SYMBOL_PROP_DOUBLE_SKIP) enum ENUM_SORT_SYMBOLS_MODE { //--- Sort by integer properties SORT_BY_SYMBOL_STATUS = 0, // Sort by symbol status SORT_BY_SYMBOL_INDEX_MW, // Sort by index in the Market Watch window SORT_BY_SYMBOL_CUSTOM, // Sort by custom symbol property SORT_BY_SYMBOL_CHART_MODE, // Sort by price type for constructing bars – Bid or Last (from the ENUM_SYMBOL_CHART_MODE enumeration) SORT_BY_SYMBOL_EXIST, // Sort by the flag that a symbol with such a name exists SORT_BY_SYMBOL_SELECT, // Sort by the flag indicating that a symbol is selected in Market Watch SORT_BY_SYMBOL_VISIBLE, // Sort by the flag indicating that a selected symbol is displayed in Market Watch SORT_BY_SYMBOL_SESSION_DEALS, // Sort by the number of deals in the current session SORT_BY_SYMBOL_SESSION_BUY_ORDERS, // Sort by the total number of current buy orders SORT_BY_SYMBOL_SESSION_SELL_ORDERS, // Sort by the total number of current sell orders SORT_BY_SYMBOL_VOLUME, // Sort by last deal volume SORT_BY_SYMBOL_VOLUMEHIGH, // Sort by maximum volume for a day SORT_BY_SYMBOL_VOLUMELOW, // Sort by minimum volume for a day SORT_BY_SYMBOL_TIME, // Sort by the last quote time SORT_BY_SYMBOL_DIGITS, // Sort by a number of decimal places SORT_BY_SYMBOL_DIGITS_LOT, // Sort by a number of decimal places in a lot SORT_BY_SYMBOL_SPREAD, // Sort by spread in points SORT_BY_SYMBOL_SPREAD_FLOAT, // Sort by floating spread SORT_BY_SYMBOL_TICKS_BOOKDEPTH, // Sort by a maximum number of requests displayed in the market depth SORT_BY_SYMBOL_TRADE_CALC_MODE, // Sort by contract price calculation method (from the ENUM_SYMBOL_CALC_MODE enumeration) SORT_BY_SYMBOL_TRADE_MODE, // Sort by order execution type (from the ENUM_SYMBOL_TRADE_MODE enumeration) SORT_BY_SYMBOL_START_TIME, // Sort by an instrument trading start date (usually used for futures) SORT_BY_SYMBOL_EXPIRATION_TIME, // Sort by an instrument trading end date (usually used for futures) SORT_BY_SYMBOL_TRADE_STOPS_LEVEL, // Sort by the minimum indent from the current close price (in points) for setting Stop orders SORT_BY_SYMBOL_TRADE_FREEZE_LEVEL, // Sort by trade operation freeze distance (in points) SORT_BY_SYMBOL_TRADE_EXEMODE, // Sort by trade execution mode (from the ENUM_SYMBOL_TRADE_EXECUTION enumeration) SORT_BY_SYMBOL_SWAP_MODE, // Sort by swap calculation model (from the ENUM_SYMBOL_SWAP_MODE enumeration) SORT_BY_SYMBOL_SWAP_ROLLOVER3DAYS, // Sort by week day for accruing a triple swap (from the ENUM_DAY_OF_WEEK enumeration) SORT_BY_SYMBOL_MARGIN_HEDGED_USE_LEG, // Sort by the calculation mode of a hedged margin using the larger leg (Buy or Sell) SORT_BY_SYMBOL_EXPIRATION_MODE, // Sort by flags of allowed order expiration modes SORT_BY_SYMBOL_FILLING_MODE, // Sort by flags of allowed order filling modes SORT_BY_SYMBOL_ORDER_MODE, // Sort by flags of allowed order types SORT_BY_SYMBOL_ORDER_GTC_MODE, // Sort by StopLoss and TakeProfit orders lifetime SORT_BY_SYMBOL_OPTION_MODE, // Sort by option type (from the ENUM_SYMBOL_OPTION_MODE enumeration) SORT_BY_SYMBOL_OPTION_RIGHT, // Sort by option right (Call/Put) (from the ENUM_SYMBOL_OPTION_RIGHT enumeration) //--- Sort by real properties SORT_BY_SYMBOL_BID = FIRST_SYM_DBL_PROP, // Sort by Bid SORT_BY_SYMBOL_BIDHIGH, // Sort by maximum Bid for a day SORT_BY_SYMBOL_BIDLOW, // Sort by minimum Bid for a day SORT_BY_SYMBOL_ASK, // Sort by Ask SORT_BY_SYMBOL_ASKHIGH, // Sort by maximum Ask for a day SORT_BY_SYMBOL_ASKLOW, // Sort by minimum Ask for a day SORT_BY_SYMBOL_LAST, // Sort by the last deal price SORT_BY_SYMBOL_LASTHIGH, // Sort by maximum Last for a day SORT_BY_SYMBOL_LASTLOW, // Sort by minimum Last for a day SORT_BY_SYMBOL_VOLUME_REAL, // Sort by Volume for a day SORT_BY_SYMBOL_VOLUMEHIGH_REAL, // Sort by maximum Volume for a day SORT_BY_SYMBOL_VOLUMELOW_REAL, // Sort by minimum Volume for a day SORT_BY_SYMBOL_OPTION_STRIKE, // Sort by an option execution price SORT_BY_SYMBOL_POINT, // Sort by a single point value SORT_BY_SYMBOL_TRADE_TICK_VALUE, // Sort by SYMBOL_TRADE_TICK_VALUE_PROFIT value SORT_BY_SYMBOL_TRADE_TICK_VALUE_PROFIT, // Sort by a calculated tick price for a profitable position SORT_BY_SYMBOL_TRADE_TICK_VALUE_LOSS, // Sort by a calculated tick price for a loss-making position SORT_BY_SYMBOL_TRADE_TICK_SIZE, // Sort by a minimum price change SORT_BY_SYMBOL_TRADE_CONTRACT_SIZE, // Sort by a trading contract size SORT_BY_SYMBOL_TRADE_ACCRUED_INTEREST, // Sort by accrued interest SORT_BY_SYMBOL_TRADE_FACE_VALUE, // Sort by face value SORT_BY_SYMBOL_TRADE_LIQUIDITY_RATE, // Sort by liquidity rate SORT_BY_SYMBOL_VOLUME_MIN, // Sort by a minimum volume for performing a deal SORT_BY_SYMBOL_VOLUME_MAX, // Sort by a maximum volume for performing a deal SORT_BY_SYMBOL_VOLUME_STEP, // Sort by a minimum volume change step for deal execution SORT_BY_SYMBOL_VOLUME_LIMIT, // Sort by a maximum allowed aggregate volume of an open position and pending orders in one direction SORT_BY_SYMBOL_SWAP_LONG, // Sort by a long swap value SORT_BY_SYMBOL_SWAP_SHORT, // Sort by a short swap value SORT_BY_SYMBOL_MARGIN_INITIAL, // Sort by an initial margin SORT_BY_SYMBOL_MARGIN_MAINTENANCE, // Sort by a maintenance margin for an instrument SORT_BY_SYMBOL_MARGIN_LONG_INITIAL, // Sort by initial margin requirement applicable to Long orders SORT_BY_SYMBOL_MARGIN_BUY_STOP_INITIAL, // Sort by initial margin requirement applicable to BuyStop orders SORT_BY_SYMBOL_MARGIN_BUY_LIMIT_INITIAL, // Sort by initial margin requirement applicable to BuyLimit orders SORT_BY_SYMBOL_MARGIN_BUY_STOPLIMIT_INITIAL, // Sort by initial margin requirement applicable to BuyStopLimit orders SORT_BY_SYMBOL_MARGIN_LONG_MAINTENANCE, // Sort by maintenance margin requirement applicable to Long orders SORT_BY_SYMBOL_MARGIN_BUY_STOP_MAINTENANCE, // Sort by maintenance margin requirement applicable to BuyStop orders SORT_BY_SYMBOL_MARGIN_BUY_LIMIT_MAINTENANCE, // Sort by maintenance margin requirement applicable to BuyLimit orders SORT_BY_SYMBOL_MARGIN_BUY_STOPLIMIT_MAINTENANCE, // Sort by maintenance margin requirement applicable to BuyStopLimit orders SORT_BY_SYMBOL_MARGIN_SHORT_INITIAL, // Sort by initial margin requirement applicable to Short orders SORT_BY_SYMBOL_MARGIN_SELL_STOP_INITIAL, // Sort by initial margin requirement applicable to SellStop orders SORT_BY_SYMBOL_MARGIN_SELL_LIMIT_INITIAL, // Sort by initial margin requirement applicable to SellLimit orders SORT_BY_SYMBOL_MARGIN_SELL_STOPLIMIT_INITIAL, // Sort by initial margin requirement applicable to SellStopLimit orders SORT_BY_SYMBOL_MARGIN_SHORT_MAINTENANCE, // Sort by maintenance margin requirement applicable to Short orders SORT_BY_SYMBOL_MARGIN_SELL_STOP_MAINTENANCE, // Sort by maintenance margin requirement applicable to SellStop orders SORT_BY_SYMBOL_MARGIN_SELL_LIMIT_MAINTENANCE, // Sort by maintenance margin requirement applicable to SellLimit orders SORT_BY_SYMBOL_MARGIN_SELL_STOPLIMIT_MAINTENANCE, // Sort by maintenance margin requirement applicable to SellStopLimit orders SORT_BY_SYMBOL_SESSION_VOLUME, // Sort by summary volume of the current session deals SORT_BY_SYMBOL_SESSION_TURNOVER, // Sort by the summary turnover of the current session SORT_BY_SYMBOL_SESSION_INTEREST, // Sort by the summary open interest SORT_BY_SYMBOL_SESSION_BUY_ORDERS_VOLUME, // Sort by the current volume of Buy orders SORT_BY_SYMBOL_SESSION_SELL_ORDERS_VOLUME, // Sort by the current volume of Sell orders SORT_BY_SYMBOL_SESSION_OPEN, // Sort by a session Open price SORT_BY_SYMBOL_SESSION_CLOSE, // Sort by a session Close price SORT_BY_SYMBOL_SESSION_AW, // Sort by an average weighted price of the current session SORT_BY_SYMBOL_SESSION_PRICE_SETTLEMENT, // Sort by a settlement price of the current session SORT_BY_SYMBOL_SESSION_PRICE_LIMIT_MIN, // Sort by a minimum price of the current session SORT_BY_SYMBOL_SESSION_PRICE_LIMIT_MAX, // Sort by a maximum price of the current session SORT_BY_SYMBOL_MARGIN_HEDGED, // Sort by a contract size or a margin value per one lot of hedged positions //--- Sort by string properties SORT_BY_SYMBOL_NAME = FIRST_SYM_STR_PROP, // Sort by a symbol name SORT_BY_SYMBOL_BASIS, // Sort by an underlying asset of a derivative SORT_BY_SYMBOL_CURRENCY_BASE, // Sort by a base currency of a symbol SORT_BY_SYMBOL_CURRENCY_PROFIT, // Sort by a profit currency SORT_BY_SYMBOL_CURRENCY_MARGIN, // Sort by a margin currency SORT_BY_SYMBOL_BANK, // Sort by a feeder of the current quote SORT_BY_SYMBOL_DESCRIPTION, // Sort by a symbol string description SORT_BY_SYMBOL_FORMULA, // Sort by the formula used for custom symbol pricing SORT_BY_SYMBOL_ISIN, // Sort by the name of a symbol in the ISIN system SORT_BY_SYMBOL_PAGE, // Sort by an address of the web page containing symbol information SORT_BY_SYMBOL_PATH // Sort by a path in the symbol tree }; //+------------------------------------------------------------------+
Ya hemos terminado con el archivo Defines.mqh.
Ahora debemos mejorar la clase del objeto de símbolo. Dado que vamos a monitorear ciertas propiedades del símbolo para ver si han cambiado, necesitaremos comparar el valor actual con el anterior, ya sea en magnitudes absolutas, ya sea comprobando si se ha superado un cierto valor umbral. Para ello, deberemos crear una estructura de propiedades del símbolo y comparar los campos de la estructura de los valores actuales con los campos de la estructura de los valores pasados. Ya discutimos la definición de los eventos de objeto al implementar el seguimiento de eventos de la cuenta. Aquí haremos lo mismo, salvo que ahora tendremos ya preparados en el objeto básico los métodos para guardar y enviar eventos al programa.
Incluimos en la clase CSymbol el archivo del objeto básico, creamos en la sección privada de la clase la estructura de las propiedades del símbolo investigadas y declaramos las dos variables de esta estructua para el guardado del estado actual y pasado de las propiedades del símbolo:
//+------------------------------------------------------------------+ //| Symbol.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" #property strict // Necessary for mql4 //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "..\BaseObj.mqh" //+------------------------------------------------------------------+ //| Abstract symbol class | //+------------------------------------------------------------------+ class CSymbol : public CBaseObj { private: struct MqlDataSymbol { //--- Symbol integer properties ENUM_SYMBOL_TRADE_MODE trade_mode; // SYMBOL_TRADE_MODE Order filling modes long session_deals; // SYMBOL_SESSION_DEALS The number of deals in the current session long session_buy_orders; // SYMBOL_SESSION_BUY_ORDERS The total number of current buy orders long session_sell_orders; // SYMBOL_SESSION_SELL_ORDERS The total number of current sell orders long volume; // SYMBOL_VOLUME Last deal volume long volume_high_day; // SYMBOL_VOLUMEHIGH Maximum volume within a day long volume_low_day; // SYMBOL_VOLUMELOW Minimum volume within a day int spread; // SYMBOL_SPREAD Spread in points int stops_level; // SYMBOL_TRADE_STOPS_LEVEL Minimum distance in points from the current close price for setting Stop orders int freeze_level; // SYMBOL_TRADE_FREEZE_LEVEL Freeze distance for trading operations (in points) //--- Symbol real properties double bid_last; // SYMBOL_BID/SYMBOL_LAST Bid - the best sell offer/Last deal price double bid_last_high; // SYMBOL_BIDHIGH/SYMBOL_LASTHIGH Maximum Bid within the day/Maximum Last per day double bid_last_low; // SYMBOL_BIDLOW/SYMBOL_LASTLOW Minimum Bid within the day/Minimum Last per day double ask; // SYMBOL_ASK Ask - nest buy offer double ask_high; // SYMBOL_ASKHIGH Maximum Ask of the day double ask_low; // SYMBOL_ASKLOW Minimum Ask of the day double volume_real_day; // SYMBOL_VOLUME_REAL Real Volume of the day double volume_high_real_day; // SYMBOL_VOLUMEHIGH_REAL Maximum real Volume of the day double volume_low_real_day; // SYMBOL_VOLUMELOW_REAL Minimum real Volume of the day double option_strike; // SYMBOL_OPTION_STRIKE Strike price double volume_limit; // SYMBOL_VOLUME_LIMIT Maximum permissible total volume for a position and pending orders in one direction double swap_long; // SYMBOL_SWAP_LONG Long swap value double swap_short; // SYMBOL_SWAP_SHORT Short swap value double session_volume; // SYMBOL_SESSION_VOLUME The total volume of deals in the current session double session_turnover; // SYMBOL_SESSION_TURNOVER The total turnover in the current session double session_interest; // SYMBOL_SESSION_INTEREST The total volume of open positions double session_buy_ord_volume; // SYMBOL_SESSION_BUY_ORDERS_VOLUME The total volume of Buy orders at the moment double session_sell_ord_volume; // SYMBOL_SESSION_SELL_ORDERS_VOLUME The total volume of Sell orders at the moment double session_open; // SYMBOL_SESSION_OPEN Session open price double session_close; // SYMBOL_SESSION_CLOSE Session close price double session_aw; // SYMBOL_SESSION_AW The average weighted price of the session }; MqlDataSymbol m_struct_curr_symbol; // Current symbol data MqlDataSymbol m_struct_prev_symbol; // Previous symbol data //---
A continuación, declaramos las variables de miembro de clase para guardar las magnitudes controladas establecidas del cambio de las propiedades, las magnitudes del cambio sucedido y las banderas de presencia de los eventos investigados:
//--- Execution bool m_is_change_trade_mode; // Flag of changing trading mode for a symbol //--- Current session deals long m_control_session_deals_inc; // Controlled value of the growth of the number of deals long m_control_session_deals_dec; // Controlled value of the decrease in the number of deals long m_changed_session_deals_value; // Value of change in the number of deals bool m_is_change_session_deals_inc; // Flag of a change in the number of deals exceeding the growth value bool m_is_change_session_deals_dec; // Flag of a change in the number of deals exceeding the decrease value //--- Buy orders of the current session long m_control_session_buy_ord_inc; // Controlled value of the growth of the number of Buy orders long m_control_session_buy_ord_dec; // Controlled value of the decrease in the number of Buy orders long m_changed_session_buy_ord_value; // Buy orders change value bool m_is_change_session_buy_ord_inc; // Flag of a change in the number of Buy orders exceeding the growth value bool m_is_change_session_buy_ord_dec; // Flag of a change in the number of Buy orders being less than the growth value //--- Sell orders of the current session long m_control_session_sell_ord_inc; // Controlled value of the growth of the number of Sell orders long m_control_session_sell_ord_dec; // Controlled value of the decrease in the number of Sell orders long m_changed_session_sell_ord_value; // Sell orders change value bool m_is_change_session_sell_ord_inc; // Flag of a change in the number of Sell orders exceeding the growth value bool m_is_change_session_sell_ord_dec; // Flag of a change in the number of Sell orders exceeding the decrease value //--- Volume of the last deal long m_control_volume_inc; // Controlled value of the volume growth in the last deal long m_control_volume_dec; // Controlled value of the volume decrease in the last deal long m_changed_volume_value; // Value of the volume change in the last deal bool m_is_change_volume_inc; // Flag of the volume change in the last deal exceeding the growth value bool m_is_change_volume_dec; // Flag of the volume change in the last deal being less than the growth value //--- Maximum volume within a day long m_control_volume_high_day_inc; // Controlled value of the maximum volume growth for a day long m_control_volume_high_day_dec; // Controlled value of the maximum volume decrease for a day long m_changed_volume_high_day_value; // Maximum volume change value within a day bool m_is_change_volume_high_day_inc; // Flag of the maximum day volume exceeding the growth value bool m_is_change_volume_high_day_dec; // Flag of the maximum day volume exceeding the decrease value //--- Minimum volume within a day long m_control_volume_low_day_inc; // Controlled value of the minimum volume growth for a day long m_control_volume_low_day_dec; // Controlled value of the minimum volume decrease for a day long m_changed_volume_low_day_value; // Minimum volume change value within a day bool m_is_change_volume_low_day_inc; // Flag of the minimum day volume exceeding the growth value bool m_is_change_volume_low_day_dec; // Flag of the minimum day volume exceeding the decrease value //--- Spread int m_control_spread_inc; // Controlled spread growth value in points int m_control_spread_dec; // Controlled spread decrease value in points int m_changed_spread_value; // Spread change value in points bool m_is_change_spread_inc; // Flag of spread change in points exceeding the growth value bool m_is_change_spread_dec; // Flag of spread change in points exceeding the decrease value //--- StopLevel int m_control_stops_level_inc; // Controlled StopLevel growth value in points int m_control_stops_level_dec; // Controlled StopLevel decrease value in points int m_changed_stops_level_value; // StopLevel change value in points bool m_is_change_stops_level_inc; // Flag of StopLevel change in points exceeding the growth value bool m_is_change_stops_level_dec; // Flag of StopLevel change in points exceeding the decrease value //--- Freeze distance int m_control_freeze_level_inc; // Controlled FreezeLevel growth value in points int m_control_freeze_level_dec; // Controlled FreezeLevel decrease value in points int m_changed_freeze_level_value; // FreezeLevel change value in points bool m_is_change_freeze_level_inc; // Flag of FreezeLevel change in points exceeding the growth value bool m_is_change_freeze_level_dec; // Flag of FreezeLevel change in points exceeding the decrease value //--- Bid/Last double m_control_bid_last_inc; // Controlled value of Bid or Last price growth double m_control_bid_last_dec; // Controlled value of Bid or Last price decrease double m_changed_bid_last_value; // Bid or Last price change value bool m_is_change_bid_last_inc; // Flag of Bid or Last price change exceeding the growth value bool m_is_change_bid_last_dec; // Flag of Bid or Last price change exceeding the decrease value //--- Maximum Bid/Last of the day double m_control_bid_last_high_inc; // Controlled growth value of the maximum Bid or Last price of the day double m_control_bid_last_high_dec; // Controlled decrease value of the maximum Bid or Last price of the day double m_changed_bid_last_high_value; // Maximum Bid or Last change value for the day bool m_is_change_bid_last_high_inc; // Flag of the maximum Bid or Last price change for the day exceeding the growth value bool m_is_change_bid_last_high_dec; // Flag of the maximum Bid or Last price change for the day exceeding the decrease value //--- Minimum Bid/Last of the day double m_control_bid_last_low_inc; // Controlled growth value of the minimum Bid or Last price of the day double m_control_bid_last_low_dec; // Controlled decrease value of the minimum Bid or Last price of the day double m_changed_bid_last_low_value; // Minimum Bid or Last change value for the day bool m_is_change_bid_last_low_inc; // Flag of the minimum Bid or Last price change for the day exceeding the growth value bool m_is_change_bid_last_low_dec; // Flag of the minimum Bid or Last price change for the day exceeding the decrease value //--- Ask double m_control_ask_inc; // Controlled value of the Ask price growth double m_control_ask_dec; // Controlled value of the Ask price decrease double m_changed_ask_value; // Ask price change value bool m_is_change_ask_inc; // Flag of the Ask price change exceeding the growth value bool m_is_change_ask_dec; // Flag of the Ask price change exceeding the decrease value //--- Maximum Ask price for the day double m_control_ask_high_inc; // Controlled growth value of the maximum Ask price of the day double m_control_ask_high_dec; // Controlled decrease value of the maximum Ask price of the day double m_changed_ask_high_value; // Maximum Ask price change value for the day bool m_is_change_ask_high_inc; // Flag of the maximum Ask price change for the day exceeding the growth value bool m_is_change_ask_high_dec; // Flag of the maximum Ask price change for the day exceeding the decrease value //--- Minimum Ask price for the day double m_control_ask_low_inc; // Controlled growth value of the minimum Ask price of the day double m_control_ask_low_dec; // Controlled decrease value of the minimum Ask price of the day double m_changed_ask_low_value; // Minimum Ask price change value for the day bool m_is_change_ask_low_inc; // Flag of the minimum Ask price change for the day exceeding the growth value bool m_is_change_ask_low_dec; // Flag of the minimum Ask price change for the day exceeding the decrease value //--- Real Volume for the day double m_control_volume_real_inc; // Controlled value of the real volume growth of the day double m_control_volume_real_dec; // Controlled value of the real volume decrease of the day double m_changed_volume_real_value; // Real volume change value of the day bool m_is_change_volume_real_inc; // Flag of the real volume change for the day exceeding the growth value bool m_is_change_volume_real_dec; // Flag of the real volume change for the day exceeding the decrease value //--- Maximum real volume for the day double m_control_volume_high_real_day_inc; // Controlled value of the maximum real volume growth of the day double m_control_volume_high_real_day_dec; // Controlled value of the maximum real volume decrease of the day double m_changed_volume_high_real_day_value; // Maximum real volume change value of the day bool m_is_change_volume_high_real_day_inc; // Flag of the maximum real volume change for the day exceeding the growth value bool m_is_change_volume_high_real_day_dec; // Flag of the maximum real volume change for the day exceeding the decrease value //--- Minimum real volume for the day double m_control_volume_low_real_day_inc; // Controlled value of the minimum real volume growth of the day double m_control_volume_low_real_day_dec; // Controlled value of the minimum real volume decrease of the day double m_changed_volume_low_real_day_value; // Minimum real volume change value of the day bool m_is_change_volume_low_real_day_inc; // Flag of the minimum real volume change for the day exceeding the growth value bool m_is_change_volume_low_real_day_dec; // Flag of the minimum real volume change for the day exceeding the decrease value //--- Strike price double m_control_option_strike_inc; // Controlled value of the strike price growth double m_control_option_strike_dec; // Controlled value of the strike price decrease double m_changed_option_strike_value; // Strike price change value bool m_is_change_option_strike_inc; // Flag of the strike price change exceeding the growth value bool m_is_change_option_strike_dec; // Flag of the strike price change exceeding the decrease value //--- Total volume of positions and orders double m_changed_volume_limit_value; // Minimum total volume change value bool m_is_change_volume_limit_inc; // Flag of the minimum total volume increase bool m_is_change_volume_limit_dec; // Flag of the minimum total volume decrease //--- Swap long double m_changed_swap_long_value; // Swap long change value bool m_is_change_swap_long_inc; // Flag of the swap long increase bool m_is_change_swap_long_dec; // Flag of the swap long decrease //--- Swap short double m_changed_swap_short_value; // Swap short change value bool m_is_change_swap_short_inc; // Flag of the swap short increase bool m_is_change_swap_short_dec; // Flag of the swap short decrease //--- The total volume of deals in the current session double m_control_session_volume_inc; // Controlled value of the total trade volume growth in the current session double m_control_session_volume_dec; // Controlled value of the total trade volume decrease in the current session double m_changed_session_volume_value; // The total deal volume change value in the current session bool m_is_change_session_volume_inc; // Flag of total trade volume change in the current session exceeding the growth value bool m_is_change_session_volume_dec; // Flag of total trade volume change in the current session exceeding the decrease value //--- The total turnover in the current session double m_control_session_turnover_inc; // Controlled value of the total turnover growth in the current session double m_control_session_turnover_dec; // Controlled value of the total turnover decrease in the current session double m_changed_session_turnover_value; // Total turnover change value in the current session bool m_is_change_session_turnover_inc; // Flag of total turnover change in the current session exceeding the growth value bool m_is_change_session_turnover_dec; // Flag of total turnover change in the current session exceeding the decrease value //--- The total volume of open positions double m_control_session_interest_inc; // Controlled value of the total open position volume growth in the current session double m_control_session_interest_dec; // Controlled value of the total open position volume decrease in the current session double m_changed_session_interest_value; // Change value of the open positions total volume in the current session bool m_is_change_session_interest_inc; // Flag of total open positions' volume change in the current session exceeding the growth value bool m_is_change_session_interest_dec; // Flag of total open positions' volume change in the current session exceeding the decrease value //--- The total volume of Buy orders at the moment double m_control_session_buy_ord_volume_inc; // Controlled value of the current total buy order volume growth double m_control_session_buy_ord_volume_dec; // Controlled value of the current total buy order volume decrease double m_changed_session_buy_ord_volume_value; // Change value of the current total buy order volume bool m_is_change_session_buy_ord_volume_inc; // Flag of changing the current total buy orders volume exceeding the growth value bool m_is_change_session_buy_ord_volume_dec; // Flag of changing the current total buy orders volume exceeding the decrease value //--- The total volume of Sell orders at the moment double m_control_session_sell_ord_volume_inc; // Controlled value of the current total sell order volume growth double m_control_session_sell_ord_volume_dec; // Controlled value of the current total sell order volume decrease double m_changed_session_sell_ord_volume_value; // Change value of the current total sell order volume bool m_is_change_session_sell_ord_volume_inc; // Flag of changing the current total sell orders volume exceeding the growth value bool m_is_change_session_sell_ord_volume_dec; // Flag of changing the current total sell orders volume exceeding the decrease value //--- Session open price double m_control_session_open_inc; // Controlled value of the session open price growth double m_control_session_open_dec; // Controlled value of the session open price decrease double m_changed_session_open_value; // Session open price change value bool m_is_change_session_open_inc; // Flag of the session open price change exceeding the growth value bool m_is_change_session_open_dec; // Flag of the session open price change exceeding the decrease value //--- Session close price double m_control_session_close_inc; // Controlled value of the session close price growth double m_control_session_close_dec; // Controlled value of the session close price decrease double m_changed_session_close_value; // Session close price change value bool m_is_change_session_close_inc; // Flag of the session close price change exceeding the growth value bool m_is_change_session_close_dec; // Flag of the session close price change exceeding the decrease value //--- The average weighted session price double m_control_session_aw_inc; // Controlled value of the average weighted session price growth double m_control_session_aw_dec; // Controlled value of the average weighted session price decrease double m_changed_session_aw_value; // The average weighted session price change value bool m_is_change_session_aw_inc; // Flag of the average weighted session price change value exceeding the growth value bool m_is_change_session_aw_dec; // Flag of the average weighted session price change value exceeding the decrease value
Declaramos en la sección privada de la clase los métodos (ya declarados en la clase básica CBaseObj) de inicialización de las variables de las propiedades monitoreadas y controladas del símbolo, el método de comprobación del cambio de las propiedades que retorna el código del evento y el método que establece el tipo de evento según su código y que registra un evento en la lista de eventos:
//--- Initialize the variables of (1) tracked, (2) controlled symbol data virtual void InitChangesParams(void); virtual void InitControlsParams(void); //--- Check symbol changes, return a change code virtual int SetEventCode(void); //--- Set an event type and fill in the event list virtual void SetTypeEvent(void);
Los implementamos de inmediato fuera del cuerpo de la clase.
Método de inicialización de las propiedades investigadas de un símbolo:
//+------------------------------------------------------------------+ //| Initialize the variables of tracked symbol data | //+------------------------------------------------------------------+ void CSymbol::InitChangesParams(void) { //--- List and code of changes this.m_list_events.Clear(); // Clear the change list this.m_list_events.Sort(); // Sort the change list //--- Execution this.m_is_change_trade_mode=false; // Flag of changing trading mode for a symbol //--- Current session deals this.m_changed_session_deals_value=0; // Value of change in the number of deals this.m_is_change_session_deals_inc=false; // Flag of a change in the number of deals exceeding the growth value this.m_is_change_session_deals_dec=false; // Flag of a change in the number of deals exceeding the decrease value //--- Buy orders of the current session this.m_changed_session_buy_ord_value=0; // Buy orders change value this.m_is_change_session_buy_ord_inc=false; // Flag of a change in the number of Buy orders exceeding the growth value this.m_is_change_session_buy_ord_dec=false; // Flag of a change in the number of Buy orders exceeding the decrease value //--- Sell orders of the current session this.m_changed_session_sell_ord_value=0; // Sell orders change value this.m_is_change_session_sell_ord_inc=false; // Flag of a change in the number of Sell orders exceeding the growth value this.m_is_change_session_sell_ord_dec=false; // Flag of a change in the number of Sell orders exceeding the decrease value //--- Volume of the last deal this.m_changed_volume_value=0; // Value of the volume change in the last deal this.m_is_change_volume_inc=false; // Flag of the volume change in the last deal exceeding the growth value this.m_is_change_volume_dec=false; // Flag of the volume change in the last deal exceeding the decrease value //--- Maximum volume within a day this.m_changed_volume_high_day_value=0; // Maximum volume change value within a day this.m_is_change_volume_high_day_inc=false; // Flag of the maximum day volume exceeding the growth value this.m_is_change_volume_high_day_dec=false; // Flag of the maximum day volume exceeding the decrease value //--- Minimum volume within a day this.m_changed_volume_low_day_value=0; // Minimum volume change value within a day this.m_is_change_volume_low_day_inc=false; // Flag of the minimum day volume exceeding the growth value this.m_is_change_volume_low_day_dec=false; // Flag of the minimum day volume exceeding the decrease value //--- Spread this.m_changed_spread_value=0; // Spread change value in points this.m_is_change_spread_inc=false; // Flag of spread change in points exceeding the growth value this.m_is_change_spread_dec=false; // Flag of spread change in points exceeding the decrease value //--- StopLevel this.m_changed_stops_level_value=0; // StopLevel change value in points this.m_is_change_stops_level_inc=false; // Flag of StopLevel change in points exceeding the growth value this.m_is_change_stops_level_dec=false; // Flag of StopLevel change in points exceeding the decrease value //--- Freeze distance this.m_changed_freeze_level_value=0; // FreezeLevel change value in points this.m_is_change_freeze_level_inc=false; // Flag of FreezeLevel change in points exceeding the growth value this.m_is_change_freeze_level_dec=false; // Flag of FreezeLevel change in points exceeding the decrease value //--- Bid/Last this.m_changed_bid_last_value=0; // Bid or Last price change value this.m_is_change_bid_last_inc=false; // Flag of Bid or Last price change exceeding the growth value this.m_is_change_bid_last_dec=false; // Flag of Bid or Last price change exceeding the decrease value //--- Maximum Bid/Last of the day this.m_changed_bid_last_high_value=0; // Maximum Bid or Last change value for the day this.m_is_change_bid_last_high_inc=false; // Flag of the maximum Bid or Last price change for the day exceeding the growth value this.m_is_change_bid_last_high_dec=false; // Flag of the maximum Bid or Last price change for the day exceeding the decrease value //--- Minimum Bid/Last of the day this.m_changed_bid_last_low_value=0; // Minimum Bid or Last change value for the day this.m_is_change_bid_last_low_inc=false; // Flag of the minimum Bid or Last price change for the day exceeding the growth value this.m_is_change_bid_last_low_dec=false; // Flag of the minimum Bid or Last price change for the day exceeding the decrease value //--- Ask this.m_changed_ask_value=0; // Ask price change value this.m_is_change_ask_inc=false; // Flag of the Ask price change exceeding the growth value this.m_is_change_ask_dec=false; // Flag of the Ask price change exceeding the decrease value //--- Maximum Ask price for the day this.m_changed_ask_high_value=0; // Maximum Ask price change value for the day this.m_is_change_ask_high_inc=false; // Flag of the maximum day Ask exceeding the growth value this.m_is_change_ask_high_dec=false; // Flag of the maximum day Ask exceeding the decrease value //--- Minimum Ask price for the day this.m_changed_ask_low_value=0; // Minimum Ask price change value for the day this.m_is_change_ask_low_inc=false; // Flag of the minimum Ask volume exceeding the growth value this.m_is_change_ask_low_dec=false; // Flag of the minimum Ask volume exceeding the decrease value //--- Real Volume for the day this.m_changed_volume_real_value=0; // Real volume change value of the day this.m_is_change_volume_real_inc=false; // Flag of the real volume change for the day exceeding the growth value this.m_is_change_volume_real_dec=false; // Flag of the real volume change for the day exceeding the decrease value //--- Maximum real volume for the day this.m_changed_volume_high_real_day_value=0; // Maximum real volume change value of the day this.m_is_change_volume_high_real_day_inc=false; // Flag of the maximum real volume change for the day exceeding the growth value this.m_is_change_volume_high_real_day_dec=false; // Flag of the maximum real volume change for the day exceeding the decrease value //--- Minimum real volume for the day this.m_changed_volume_low_real_day_value=0; // Minimum real volume change value of the day this.m_is_change_volume_low_real_day_inc=false; // Flag of the minimum real volume change for the day exceeding the growth value this.m_is_change_volume_low_real_day_dec=false; // Flag of the minimum real volume change for the day exceeding the decrease value //--- Strike price this.m_changed_option_strike_value=0; // Strike price change value this.m_is_change_option_strike_inc=false; // Flag of the strike price change exceeding the growth value this.m_is_change_option_strike_dec=false; // Flag of the strike price change exceeding the decrease value //--- Total volume of positions and orders this.m_changed_volume_limit_value=0; // Minimum total volume change value this.m_is_change_volume_limit_inc=false; // Flag of the minimum total volume increase this.m_is_change_volume_limit_dec=false; // Flag of the minimum total volume decrease //--- Swap long this.m_changed_swap_long_value=0; // Swap long change value this.m_is_change_swap_long_inc=false; // Flag of the swap long increase this.m_is_change_swap_long_dec=false; // Flag of the swap long decrease //--- Swap short this.m_changed_swap_short_value=0; // Swap short change value this.m_is_change_swap_short_inc=false; // Flag of the swap short increase this.m_is_change_swap_short_dec=false; // Flag of the swap short decrease //--- The total volume of deals in the current session this.m_changed_session_volume_value=0; // The total deal volume change value in the current session this.m_is_change_session_volume_inc=false; // Flag of total trade volume change in the current session exceeding the growth value this.m_is_change_session_volume_dec=false; // Flag of total trade volume change in the current session exceeding the decrease value //--- The total turnover in the current session this.m_changed_session_turnover_value=0; // Total turnover change value in the current session this.m_is_change_session_turnover_inc=false; // Flag of total turnover change in the current session exceeding the growth value this.m_is_change_session_turnover_dec=false; // Flag of total turnover change in the current session exceeding the decrease value //--- The total volume of open positions this.m_changed_session_interest_value=0; // Change value of the open positions total volume in the current session this.m_is_change_session_interest_inc=false; // Flag of total open positions' volume change in the current session exceeding the growth value this.m_is_change_session_interest_dec=false; // Flag of total open positions' volume change in the current session exceeding the decrease value //--- The total volume of Buy orders at the moment this.m_changed_session_buy_ord_volume_value=0; // Change value of the current total buy order volume this.m_is_change_session_buy_ord_volume_inc=false; // Flag of changing the current total buy orders volume exceeding the growth value this.m_is_change_session_buy_ord_volume_dec=false; // Flag of changing the current total buy orders volume exceeding the decrease value //--- The total volume of Sell orders at the moment this.m_changed_session_sell_ord_volume_value=0; // Change value of the current total sell order volume this.m_is_change_session_sell_ord_volume_inc=false; // Flag of changing the current total sell orders volume exceeding the growth value this.m_is_change_session_sell_ord_volume_dec=false; // Flag of changing the current total sell orders volume exceeding the decrease value //--- Session open price this.m_changed_session_open_value=0; // Session open price change value this.m_is_change_session_open_inc=false; // Flag of the session open price change exceeding the growth value this.m_is_change_session_open_dec=false; // Flag of the session open price change exceeding the decrease value //--- Session close price this.m_changed_session_close_value=0; // Session close price change value this.m_is_change_session_close_inc=false; // Flag of the session close price change exceeding the growth value this.m_is_change_session_close_dec=false; // Flag of the session close price change exceeding the decrease value //--- The average weighted session price this.m_changed_session_aw_value=0; // The average weighted session price change value this.m_is_change_session_aw_inc=false; // Flag of the average weighted session price change value exceeding the growth value this.m_is_change_session_aw_dec=false; // Flag of the average weighted session price change value exceeding the decrease value } //+------------------------------------------------------------------+
En el método, simplemente se asignan los valores iniciales a las variables de las propiedades investigadas del símbolo declaradas en la sección privada de la clase.
Método de inicialización de los valores controlados de las propiedades del símbolo:
//+------------------------------------------------------------------+ //| Initialize the variables of controlled symbol data | //+------------------------------------------------------------------+ void CSymbol::InitControlsParams(void) { //--- Current session deals this.m_control_session_deals_inc=10; // Controlled value of the growth of the number of deals this.m_control_session_deals_dec=10; // Controlled value of the decrease in the number of deals //--- Buy orders of the current session this.m_control_session_buy_ord_inc=10; // Controlled value of the growth of the number of Buy orders this.m_control_session_buy_ord_dec=10; // Controlled value of the decrease in the number of Buy orders //--- Sell orders of the current session this.m_control_session_sell_ord_inc=10; // Controlled value of the growth of the number of Sell orders this.m_control_session_sell_ord_dec=10; // Controlled value of the decrease in the number of Sell orders //--- Volume of the last deal this.m_control_volume_inc=10; // Controlled value of the volume growth in the last deal this.m_control_volume_dec=10; // Controlled value of the volume decrease in the last deal //--- Maximum volume within a day this.m_control_volume_high_day_inc=50; // Controlled value of the maximum volume growth for a day this.m_control_volume_high_day_dec=50; // Controlled value of the maximum volume decrease for a day //--- Minimum volume within a day this.m_control_volume_low_day_inc=50; // Controlled value of the minimum volume growth for a day this.m_control_volume_low_day_dec=50; // Controlled value of the minimum volume decrease for a day //--- Spread this.m_control_spread_inc=2; // Controlled spread growth value in points this.m_control_spread_dec=2; // Controlled spread decrease value in points //--- StopLevel this.m_control_stops_level_inc=2; // Controlled StopLevel growth value in points this.m_control_stops_level_dec=2; // Controlled StopLevel decrease value in points //--- Freeze distance this.m_control_freeze_level_inc=2; // Controlled FreezeLevel growth value in points this.m_control_freeze_level_dec=2; // Controlled FreezeLevel decrease value in points //--- Bid/Last this.m_control_bid_last_inc=DBL_MAX; // Controlled value of Bid or Last price growth this.m_control_bid_last_dec=DBL_MAX; // Controlled value of Bid or Last price decrease //--- Maximum Bid/Last of the day this.m_control_bid_last_high_inc=DBL_MAX; // Controlled growth value of the maximum Bid or Last price of the day this.m_control_bid_last_high_dec=DBL_MAX; // Controlled decrease value of the maximum Bid or Last price of the day //--- Minimum Bid/Last of the day this.m_control_bid_last_low_inc=DBL_MAX; // Controlled growth value of the minimum Bid or Last price of the day this.m_control_bid_last_low_dec=DBL_MAX; // Controlled decrease value of the minimum Bid or Last price of the day //--- Ask this.m_control_ask_inc=DBL_MAX; // Controlled value of the Ask price growth this.m_control_ask_dec=DBL_MAX; // Controlled value of the Ask price decrease //--- Maximum Ask price for the day this.m_control_ask_high_inc=DBL_MAX; // Controlled growth value of the maximum Ask price of the day this.m_control_ask_high_dec=DBL_MAX; // Controlled decrease value of the maximum Ask price of the day //--- Minimum Ask price for the day this.m_control_ask_low_inc=DBL_MAX; // Controlled growth value of the minimum Ask price of the day this.m_control_ask_low_dec=DBL_MAX; // Controlled decrease value of the minimum Ask price of the day //--- Real Volume for the day this.m_control_volume_real_inc=50; // Controlled value of the real volume growth of the day this.m_control_volume_real_dec=50; // Controlled value of the real volume decrease of the day //--- Maximum real volume for the day this.m_control_volume_high_real_day_inc=20; // Controlled value of the maximum real volume growth of the day this.m_control_volume_high_real_day_dec=20; // Controlled value of the maximum real volume decrease of the day //--- Minimum real volume for the day this.m_control_volume_low_real_day_inc=10; // Controlled value of the minimum real volume growth of the day this.m_control_volume_low_real_day_dec=10; // Controlled value of the minimum real volume decrease of the day //--- Strike price this.m_control_option_strike_inc=0; // Controlled value of the strike price growth this.m_control_option_strike_dec=0; // Controlled value of the strike price decrease //--- The total volume of deals in the current session this.m_control_session_volume_inc=10; // Controlled value of the total trade volume growth in the current session this.m_control_session_volume_dec=10; // Controlled value of the total trade volume decrease in the current session //--- The total turnover in the current session this.m_control_session_turnover_inc=1000; // Controlled value of the total turnover growth in the current session this.m_control_session_turnover_dec=500; // Controlled value of the total turnover decrease in the current session //--- The total volume of open positions this.m_control_session_interest_inc=50; // Controlled value of the total open position volume growth in the current session this.m_control_session_interest_dec=20; // Controlled value of the total open position volume decrease in the current session //--- The total volume of Buy orders at the moment this.m_control_session_buy_ord_volume_inc=50; // Controlled value of the current total buy order volume growth this.m_control_session_buy_ord_volume_dec=20; // Controlled value of the current total buy order volume decrease //--- The total volume of Sell orders at the moment this.m_control_session_sell_ord_volume_inc=50; // Controlled value of the current total sell order volume growth this.m_control_session_sell_ord_volume_dec=20; // Controlled value of the current total sell order volume decrease //--- Session open price this.m_control_session_open_inc=0; // Controlled value of the session open price growth this.m_control_session_open_dec=0; // Controlled value of the session open price decrease //--- Session close price this.m_control_session_close_inc=0; // Controlled value of the session close price growth this.m_control_session_close_dec=0; // Controlled value of the session close price decrease //--- The average weighted session price this.m_control_session_aw_inc=0; // Controlled value of the average weighted session price growth this.m_control_session_aw_dec=0; // Controlled value of the average weighted session price decrease } //+------------------------------------------------------------------+
En el método, simplemente se asignan los valores iniciales a las variables de las propiedades controladas del símbolo declaradas en la sección privada de la clase. Cuando las propiedades superan los valores inscritos en estas variables, se genera el evento de cuenta correspondiente. Para desactivar el control de una propiedad, deberemos asignar a su variable el valor DBL_MAX. Para monitorear el cambio de cualquier magnitud, debemos asignar 0 a la variable.
Método que comprueba el cambio sucedido en las propiedades del símbolo y luego retorna el código del cambio sucedido:
//+------------------------------------------------------------------+ //| Check symbol changes, return a change code | //+------------------------------------------------------------------+ int CSymbol::SetEventCode(void) { this.m_event_code=SYMBOL_EVENT_FLAG_NO_EVENT; if(this.m_struct_curr_symbol.trade_mode!=this.m_struct_prev_symbol.trade_mode) this.m_event_code+=SYMBOL_EVENT_FLAG_TRADE_MODE; if(this.m_struct_curr_symbol.session_deals!=this.m_struct_prev_symbol.session_deals) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_DEALS; if(this.m_struct_curr_symbol.session_buy_orders!=this.m_struct_prev_symbol.session_buy_orders) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_BUY_ORDERS; if(this.m_struct_curr_symbol.session_sell_orders!=this.m_struct_prev_symbol.session_sell_orders) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_SELL_ORDERS; if(this.m_struct_curr_symbol.volume!=this.m_struct_prev_symbol.volume) this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME; if(this.m_struct_curr_symbol.volume_high_day!=this.m_struct_prev_symbol.volume_high_day) this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME_HIGH_DAY; if(this.m_struct_curr_symbol.volume_low_day!=this.m_struct_prev_symbol.volume_low_day) this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME_LOW_DAY; if(this.m_struct_curr_symbol.spread!=this.m_struct_prev_symbol.spread) this.m_event_code+=SYMBOL_EVENT_FLAG_SPREAD; if(this.m_struct_curr_symbol.stops_level!=this.m_struct_prev_symbol.stops_level) this.m_event_code+=SYMBOL_EVENT_FLAG_STOPLEVEL; if(this.m_struct_curr_symbol.freeze_level!=this.m_struct_prev_symbol.freeze_level) this.m_event_code+=SYMBOL_EVENT_FLAG_FREEZELEVEL; if(this.m_struct_curr_symbol.bid_last!=this.m_struct_prev_symbol.bid_last) this.m_event_code+=SYMBOL_EVENT_FLAG_BID_LAST; if(this.m_struct_curr_symbol.bid_last_high!=this.m_struct_prev_symbol.bid_last_high) this.m_event_code+=SYMBOL_EVENT_FLAG_BID_LAST_HIGH; if(this.m_struct_curr_symbol.bid_last_low!=this.m_struct_prev_symbol.bid_last_low) this.m_event_code+=SYMBOL_EVENT_FLAG_BID_LAST_LOW; if(this.m_struct_curr_symbol.ask!=this.m_struct_prev_symbol.ask) this.m_event_code+=SYMBOL_EVENT_FLAG_ASK; if(this.m_struct_curr_symbol.ask_high!=this.m_struct_prev_symbol.ask_high) this.m_event_code+=SYMBOL_EVENT_FLAG_ASK_HIGH; if(this.m_struct_curr_symbol.ask_low!=this.m_struct_prev_symbol.ask_low) this.m_event_code+=SYMBOL_EVENT_FLAG_ASK_LOW; if(this.m_struct_curr_symbol.volume_real_day!=this.m_struct_prev_symbol.volume_real_day) this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME_REAL_DAY; if(this.m_struct_curr_symbol.volume_high_real_day!=this.m_struct_prev_symbol.volume_high_real_day) this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME_HIGH_REAL_DAY; if(this.m_struct_curr_symbol.volume_low_real_day!=this.m_struct_prev_symbol.volume_low_real_day) this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME_LOW_REAL_DAY; if(this.m_struct_curr_symbol.option_strike!=this.m_struct_prev_symbol.option_strike) this.m_event_code+=SYMBOL_EVENT_FLAG_OPTION_STRIKE; if(this.m_struct_curr_symbol.volume_limit!=this.m_struct_prev_symbol.volume_limit) this.m_event_code+=SYMBOL_EVENT_FLAG_VOLUME_LIMIT; if(this.m_struct_curr_symbol.swap_long!=this.m_struct_prev_symbol.swap_long) this.m_event_code+=SYMBOL_EVENT_FLAG_SWAP_LONG; if(this.m_struct_curr_symbol.swap_short!=this.m_struct_prev_symbol.swap_short) this.m_event_code+=SYMBOL_EVENT_FLAG_SWAP_SHORT; if(this.m_struct_curr_symbol.session_volume!=this.m_struct_prev_symbol.session_volume) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_VOLUME; if(this.m_struct_curr_symbol.session_turnover!=this.m_struct_prev_symbol.session_turnover) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_TURNOVER; if(this.m_struct_curr_symbol.session_interest!=this.m_struct_prev_symbol.session_interest) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_INTEREST; if(this.m_struct_curr_symbol.session_buy_ord_volume!=this.m_struct_prev_symbol.session_buy_ord_volume) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_BUY_ORD_VOLUME; if(this.m_struct_curr_symbol.session_sell_ord_volume!=this.m_struct_prev_symbol.session_sell_ord_volume) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_SELL_ORD_VOLUME; if(this.m_struct_curr_symbol.session_open!=this.m_struct_prev_symbol.session_open) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_OPEN; if(this.m_struct_curr_symbol.session_close!=this.m_struct_prev_symbol.session_close) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_CLOSE; if(this.m_struct_curr_symbol.session_aw!=this.m_struct_prev_symbol.session_aw) this.m_event_code+=SYMBOL_EVENT_FLAG_SESSION_AW; //--- return this.m_event_code; } //+------------------------------------------------------------------+
En primer lugar, se resetea el código de evento en el método, luego se comparan los valores de los parámetros del símbolo controlados en la estructura de datos actuales y la estructura de datos pasados. Si los datos no son iguales, añadimos al código de evento la bandera correspondiente.
Método que establece el tipo de evento y registra el evento sucedido en la lista de eventos:
//+------------------------------------------------------------------+ //| Set a symbol object event type | //+------------------------------------------------------------------+ void CSymbol::SetTypeEvent(void) { this.InitChangesParams(); ENUM_SYMBOL_EVENT event_id=SYMBOL_EVENT_NO_EVENT; //--- Change of trading modes on a symbol if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_TRADE_MODE)) { event_id= ( this.TradeMode()==SYMBOL_TRADE_MODE_DISABLED ? SYMBOL_EVENT_TRADE_DISABLE : this.TradeMode()==SYMBOL_TRADE_MODE_LONGONLY ? SYMBOL_EVENT_TRADE_LONGONLY : this.TradeMode()==SYMBOL_TRADE_MODE_SHORTONLY ? SYMBOL_EVENT_TRADE_SHORTONLY : this.TradeMode()==SYMBOL_TRADE_MODE_CLOSEONLY ? SYMBOL_EVENT_TRADE_CLOSEONLY : SYMBOL_EVENT_TRADE_FULL ); this.m_is_change_trade_mode=true; if(this.EventAdd(event_id,this.TickTime(),this.TradeMode(),this.Name())) this.m_struct_prev_symbol.trade_mode=this.m_struct_curr_symbol.trade_mode; } //--- Change of the number of deals in the current session if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_DEALS)) { this.m_changed_session_deals_value=this.m_struct_curr_symbol.session_deals-this.m_struct_prev_symbol.session_deals; if(this.m_changed_session_deals_value>this.m_control_session_deals_inc) { this.m_is_change_session_deals_inc=true; event_id=SYMBOL_EVENT_SESSION_DEALS_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_deals_value,this.Name())) this.m_struct_prev_symbol.session_deals=this.m_struct_curr_symbol.session_deals; } else if(this.m_changed_session_deals_value<-this.m_control_session_deals_dec) { this.m_is_change_session_deals_dec=true; event_id=SYMBOL_EVENT_SESSION_DEALS_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_deals_value,this.Name())) this.m_struct_prev_symbol.session_deals=this.m_struct_curr_symbol.session_deals; } } //--- Change of the total number of the current buy orders if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_BUY_ORDERS)) { this.m_changed_session_buy_ord_value=this.m_struct_curr_symbol.session_buy_orders-this.m_struct_prev_symbol.session_buy_orders; if(this.m_changed_session_buy_ord_value>this.m_control_session_buy_ord_inc) { this.m_is_change_session_buy_ord_inc=true; event_id=SYMBOL_EVENT_SESSION_BUY_ORDERS_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_buy_ord_value,this.Name())) this.m_struct_prev_symbol.session_buy_orders=this.m_struct_curr_symbol.session_buy_orders; } else if(this.m_changed_session_buy_ord_value<-this.m_control_session_buy_ord_dec) { this.m_is_change_session_buy_ord_dec=true; event_id=SYMBOL_EVENT_SESSION_BUY_ORDERS_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_buy_ord_value,this.Name())) this.m_struct_prev_symbol.session_buy_orders=this.m_struct_curr_symbol.session_buy_orders; } } //--- Change of the total number of the current sell orders if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_SELL_ORDERS)) { this.m_changed_session_sell_ord_value=this.m_struct_curr_symbol.session_sell_orders-this.m_struct_prev_symbol.session_sell_orders; if(this.m_changed_session_sell_ord_value>this.m_control_session_sell_ord_inc) { this.m_is_change_session_sell_ord_inc=true; event_id=SYMBOL_EVENT_SESSION_SELL_ORDERS_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_sell_ord_value,this.Name())) this.m_struct_prev_symbol.session_sell_orders=this.m_struct_curr_symbol.session_sell_orders; } else if(this.m_changed_session_sell_ord_value<-this.m_control_session_sell_ord_dec) { this.m_is_change_session_sell_ord_dec=true; event_id=SYMBOL_EVENT_SESSION_SELL_ORDERS_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_sell_ord_value,this.Name())) this.m_struct_prev_symbol.session_sell_orders=this.m_struct_curr_symbol.session_sell_orders; } } //--- Volume change in the last deal if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME)) { this.m_changed_volume_value=this.m_struct_curr_symbol.volume-this.m_struct_prev_symbol.volume; if(this.m_changed_volume_value>this.m_control_volume_inc) { this.m_is_change_volume_inc=true; event_id=SYMBOL_EVENT_VOLUME_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_value,this.Name())) this.m_struct_prev_symbol.volume=this.m_struct_curr_symbol.volume; } else if(this.m_changed_volume_value<-this.m_control_volume_dec) { this.m_is_change_volume_dec=true; event_id=SYMBOL_EVENT_VOLUME_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_value,this.Name())) this.m_struct_prev_symbol.volume=this.m_struct_curr_symbol.volume; } } //--- Maximum volume change for a day if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME_HIGH_DAY)) { this.m_changed_volume_high_day_value=this.m_struct_curr_symbol.volume_high_day-this.m_struct_prev_symbol.volume_high_day; if(this.m_changed_volume_high_day_value>this.m_control_volume_high_day_inc) { this.m_is_change_volume_high_day_inc=true; event_id=SYMBOL_EVENT_VOLUME_HIGH_DAY_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_high_day_value,this.Name())) this.m_struct_prev_symbol.volume_high_day=this.m_struct_curr_symbol.volume_high_day; } else if(this.m_changed_volume_high_day_value<-this.m_control_volume_high_day_dec) { this.m_is_change_volume_high_day_dec=true; event_id=SYMBOL_EVENT_VOLUME_HIGH_DAY_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_high_day_value,this.Name())) this.m_struct_prev_symbol.volume_high_day=this.m_struct_curr_symbol.volume_high_day; } } //--- Minimum volume change for a day if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME_LOW_DAY)) { this.m_changed_volume_low_day_value=this.m_struct_curr_symbol.volume_low_day-this.m_struct_prev_symbol.volume_low_day; if(this.m_changed_volume_low_day_value>this.m_control_volume_low_day_inc) { this.m_is_change_volume_low_day_inc=true; event_id=SYMBOL_EVENT_VOLUME_LOW_DAY_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_low_day_value,this.Name())) this.m_struct_prev_symbol.volume_low_day=this.m_struct_curr_symbol.volume_low_day; } else if(this.m_changed_volume_low_day_value<-this.m_control_volume_low_day_dec) { this.m_is_change_volume_low_day_dec=true; event_id=SYMBOL_EVENT_VOLUME_LOW_DAY_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_low_day_value,this.Name())) this.m_struct_prev_symbol.volume_low_day=this.m_struct_curr_symbol.volume_low_day; } } //--- Spread value change in points if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SPREAD)) { this.m_changed_spread_value=this.m_struct_curr_symbol.spread-this.m_struct_prev_symbol.spread; if(this.m_changed_spread_value>this.m_control_spread_inc) { this.m_is_change_spread_inc=true; event_id=SYMBOL_EVENT_SPREAD_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_spread_value,this.Name())) this.m_struct_prev_symbol.spread=this.m_struct_curr_symbol.spread; } else if(this.m_changed_spread_value<-this.m_control_spread_dec) { this.m_is_change_spread_dec=true; event_id=SYMBOL_EVENT_SPREAD_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_spread_value,this.Name())) this.m_struct_prev_symbol.spread=this.m_struct_curr_symbol.spread; } } //--- StopLevel change in points if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_STOPLEVEL)) { this.m_changed_stops_level_value=this.m_struct_curr_symbol.stops_level-this.m_struct_prev_symbol.stops_level; if(this.m_changed_stops_level_value>this.m_control_stops_level_inc) { this.m_is_change_stops_level_inc=true; event_id=SYMBOL_EVENT_STOPLEVEL_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_stops_level_value,this.Name())) this.m_struct_prev_symbol.stops_level=this.m_struct_curr_symbol.stops_level; } else if(this.m_changed_stops_level_value<-this.m_control_stops_level_dec) { this.m_is_change_stops_level_dec=true; event_id=SYMBOL_EVENT_STOPLEVEL_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_stops_level_value,this.Name())) this.m_struct_prev_symbol.stops_level=this.m_struct_curr_symbol.stops_level; } } //--- FreezeLevel change in points if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_FREEZELEVEL)) { this.m_changed_freeze_level_value=this.m_struct_curr_symbol.freeze_level-this.m_struct_prev_symbol.freeze_level; if(this.m_changed_freeze_level_value>this.m_control_freeze_level_inc) { this.m_is_change_freeze_level_inc=true; event_id=SYMBOL_EVENT_FREEZELEVEL_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_freeze_level_value,this.Name())) this.m_struct_prev_symbol.freeze_level=this.m_struct_curr_symbol.freeze_level; } else if(this.m_changed_freeze_level_value<-this.m_control_freeze_level_dec) { this.m_is_change_freeze_level_dec=true; event_id=SYMBOL_EVENT_FREEZELEVEL_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_freeze_level_value,this.Name())) this.m_struct_prev_symbol.freeze_level=this.m_struct_curr_symbol.freeze_level; } } //--- Bid/Last price change if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_BID_LAST)) { this.m_changed_bid_last_value=this.m_struct_curr_symbol.bid_last-this.m_struct_prev_symbol.bid_last; if(this.m_changed_bid_last_value>this.m_control_bid_last_inc) { this.m_is_change_bid_last_inc=true; event_id=SYMBOL_EVENT_BID_LAST_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_bid_last_value,this.Name())) this.m_struct_prev_symbol.bid_last=this.m_struct_curr_symbol.bid_last; } else if(this.m_changed_bid_last_value<-this.m_control_bid_last_dec) { this.m_is_change_bid_last_dec=true; event_id=SYMBOL_EVENT_BID_LAST_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_bid_last_value,this.Name())) this.m_struct_prev_symbol.bid_last=this.m_struct_curr_symbol.bid_last; } } //--- Maximum Bid/Last change for a day if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_BID_LAST_HIGH)) { this.m_changed_bid_last_high_value=this.m_struct_curr_symbol.bid_last_high-this.m_struct_prev_symbol.bid_last_high; if(this.m_changed_bid_last_high_value>this.m_control_bid_last_high_inc) { this.m_is_change_bid_last_high_inc=true; event_id=SYMBOL_EVENT_BID_LAST_HIGH_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_bid_last_high_value,this.Name())) this.m_struct_prev_symbol.bid_last_high=this.m_struct_curr_symbol.bid_last_high; } else if(this.m_changed_bid_last_high_value<-this.m_control_bid_last_high_dec) { this.m_is_change_bid_last_high_dec=true; event_id=SYMBOL_EVENT_BID_LAST_HIGH_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_bid_last_high_value,this.Name())) this.m_struct_prev_symbol.bid_last_high=this.m_struct_curr_symbol.bid_last_high; } } //--- Minimum Bid/Last change for a day if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_BID_LAST_LOW)) { this.m_changed_bid_last_low_value=this.m_struct_curr_symbol.bid_last_low-this.m_struct_prev_symbol.bid_last_low; if(this.m_changed_bid_last_low_value>this.m_control_bid_last_low_inc) { this.m_is_change_bid_last_low_inc=true; event_id=SYMBOL_EVENT_BID_LAST_LOW_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_bid_last_low_value,this.Name())) this.m_struct_prev_symbol.bid_last_low=this.m_struct_curr_symbol.bid_last_low; } else if(this.m_changed_bid_last_low_value<-this.m_control_bid_last_low_dec) { this.m_is_change_bid_last_low_dec=true; event_id=SYMBOL_EVENT_BID_LAST_LOW_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_bid_last_low_value,this.Name())) this.m_struct_prev_symbol.bid_last_low=this.m_struct_curr_symbol.bid_last_low; } } //--- Ask price change if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_ASK)) { this.m_changed_ask_value=this.m_struct_curr_symbol.ask-this.m_struct_prev_symbol.ask; if(this.m_changed_ask_value>this.m_control_ask_inc) { this.m_is_change_ask_inc=true; event_id=SYMBOL_EVENT_ASK_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_ask_value,this.Name())) this.m_struct_prev_symbol.ask=this.m_struct_curr_symbol.ask; } else if(this.m_changed_ask_value<-this.m_control_ask_dec) { this.m_is_change_ask_dec=true; event_id=SYMBOL_EVENT_ASK_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_ask_value,this.Name())) this.m_struct_prev_symbol.ask=this.m_struct_curr_symbol.ask; } } //--- Maximum As change for a day if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_ASK_HIGH)) { this.m_changed_ask_high_value=this.m_struct_curr_symbol.ask_high-this.m_struct_prev_symbol.ask_high; if(this.m_changed_ask_high_value>this.m_control_ask_high_inc) { this.m_is_change_ask_high_inc=true; event_id=SYMBOL_EVENT_ASK_HIGH_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_ask_high_value,this.Name())) this.m_struct_prev_symbol.ask_high=this.m_struct_curr_symbol.ask_high; } else if(this.m_changed_ask_high_value<-this.m_control_ask_high_dec) { this.m_is_change_ask_high_dec=true; event_id=SYMBOL_EVENT_ASK_HIGH_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_ask_high_value,this.Name())) this.m_struct_prev_symbol.ask_high=this.m_struct_curr_symbol.ask_high; } } //--- Minimum Ask change for a day if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_ASK_LOW)) { this.m_changed_ask_low_value=this.m_struct_curr_symbol.ask_low-this.m_struct_prev_symbol.ask_low; if(this.m_changed_ask_low_value>this.m_control_ask_low_inc) { this.m_is_change_ask_low_inc=true; event_id=SYMBOL_EVENT_ASK_LOW_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_ask_low_value,this.Name())) this.m_struct_prev_symbol.ask_low=this.m_struct_curr_symbol.ask_low; } else if(this.m_changed_ask_low_value<-this.m_control_ask_low_dec) { this.m_is_change_ask_low_dec=true; event_id=SYMBOL_EVENT_ASK_LOW_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_ask_low_value,this.Name())) this.m_struct_prev_symbol.ask_low=this.m_struct_curr_symbol.ask_low; } } //--- Real volume change for a day if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME_REAL_DAY)) { this.m_changed_volume_real_value=this.m_struct_curr_symbol.volume_real_day-this.m_struct_prev_symbol.volume_real_day; if(this.m_changed_volume_real_value>this.m_control_volume_real_inc) { this.m_is_change_volume_real_inc=true; event_id=SYMBOL_EVENT_VOLUME_REAL_DAY_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_real_value,this.Name())) this.m_struct_prev_symbol.volume_real_day=this.m_struct_curr_symbol.volume_real_day; } else if(this.m_changed_volume_real_value<-this.m_control_volume_real_dec) { this.m_is_change_volume_real_dec=true; event_id=SYMBOL_EVENT_VOLUME_REAL_DAY_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_real_value,this.Name())) this.m_struct_prev_symbol.volume_real_day=this.m_struct_curr_symbol.volume_real_day; } } //--- Maximum real volume change for a day if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME_HIGH_REAL_DAY)) { this.m_changed_volume_high_real_day_value=this.m_struct_curr_symbol.volume_high_real_day-this.m_struct_prev_symbol.volume_high_real_day; if(this.m_changed_volume_high_real_day_value>this.m_control_volume_high_real_day_inc) { this.m_is_change_volume_high_real_day_inc=true; event_id=SYMBOL_EVENT_VOLUME_HIGH_REAL_DAY_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_high_real_day_value,this.Name())) this.m_struct_prev_symbol.volume_high_real_day=this.m_struct_curr_symbol.volume_high_real_day; } else if(this.m_changed_volume_high_real_day_value<-this.m_control_volume_high_real_day_dec) { this.m_is_change_volume_high_real_day_dec=true; event_id=SYMBOL_EVENT_VOLUME_HIGH_REAL_DAY_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_high_real_day_value,this.Name())) this.m_struct_prev_symbol.volume_high_real_day=this.m_struct_curr_symbol.volume_high_real_day; } } //--- Minimum real volume change for a day if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME_LOW_REAL_DAY)) { this.m_changed_volume_low_real_day_value=this.m_struct_curr_symbol.volume_low_real_day-this.m_struct_prev_symbol.volume_low_real_day; if(this.m_changed_volume_low_real_day_value>this.m_control_volume_low_real_day_inc) { this.m_is_change_volume_low_real_day_inc=true; event_id=SYMBOL_EVENT_VOLUME_LOW_REAL_DAY_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_low_real_day_value,this.Name())) this.m_struct_prev_symbol.volume_low_real_day=this.m_struct_curr_symbol.volume_low_real_day; } else if(this.m_changed_volume_low_real_day_value<-this.m_control_volume_low_real_day_dec) { this.m_is_change_volume_low_real_day_dec=true; event_id=SYMBOL_EVENT_VOLUME_LOW_REAL_DAY_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_low_real_day_value,this.Name())) this.m_struct_prev_symbol.volume_low_real_day=this.m_struct_curr_symbol.volume_low_real_day; } } //--- Strike price change if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_OPTION_STRIKE)) { this.m_changed_option_strike_value=this.m_struct_curr_symbol.option_strike-this.m_struct_prev_symbol.option_strike; if(this.m_changed_option_strike_value>this.m_control_option_strike_inc) { this.m_is_change_option_strike_inc=true; event_id=SYMBOL_EVENT_OPTION_STRIKE_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_option_strike_value,this.Name())) this.m_struct_prev_symbol.option_strike=this.m_struct_curr_symbol.option_strike; } else if(this.m_changed_option_strike_value<-this.m_control_option_strike_dec) { this.m_is_change_option_strike_dec=true; event_id=SYMBOL_EVENT_OPTION_STRIKE_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_option_strike_value,this.Name())) this.m_struct_prev_symbol.option_strike=this.m_struct_curr_symbol.option_strike; } } //--- Change of the maximum available total position volume and pending orders in one direction if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_VOLUME_LIMIT)) { this.m_changed_volume_limit_value=this.m_struct_curr_symbol.volume_limit-this.m_struct_prev_symbol.volume_limit; if(this.m_changed_volume_limit_value>0) { this.m_is_change_volume_limit_inc=true; event_id=SYMBOL_EVENT_VOLUME_LIMIT_INC; } else { this.m_is_change_volume_limit_dec=true; event_id=SYMBOL_EVENT_VOLUME_LIMIT_DEC; } if(this.EventAdd(event_id,this.TickTime(),this.m_changed_volume_limit_value,this.Name())) this.m_struct_prev_symbol.volume_limit=this.m_struct_curr_symbol.volume_limit; } //--- Swap long change if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SWAP_LONG)) { this.m_changed_swap_long_value=this.m_struct_curr_symbol.swap_long-this.m_struct_prev_symbol.swap_long; if(this.m_changed_swap_long_value>0) { this.m_is_change_swap_long_inc=true; event_id=SYMBOL_EVENT_SWAP_LONG_INC; } else { this.m_is_change_swap_long_dec=true; event_id=SYMBOL_EVENT_SWAP_LONG_DEC; } if(this.EventAdd(event_id,this.TickTime(),this.m_changed_swap_long_value,this.Name())) this.m_struct_prev_symbol.swap_long=this.m_struct_curr_symbol.swap_long; } //--- Swap short change if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SWAP_SHORT)) { this.m_changed_swap_short_value=this.m_struct_curr_symbol.swap_short-this.m_struct_prev_symbol.swap_short; if(this.m_changed_swap_short_value>0) { this.m_is_change_swap_short_inc=true; event_id=SYMBOL_EVENT_SWAP_SHORT_INC; } else { this.m_is_change_swap_short_dec=true; event_id=SYMBOL_EVENT_SWAP_SHORT_DEC; } if(this.EventAdd(event_id,this.TickTime(),this.m_changed_swap_short_value,this.Name())) this.m_struct_prev_symbol.swap_short=this.m_struct_curr_symbol.swap_short; } //--- Change of the total volume of deals during the current session if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_VOLUME)) { this.m_changed_session_volume_value=this.m_struct_curr_symbol.session_volume-this.m_struct_prev_symbol.session_volume; if(this.m_changed_session_volume_value>this.m_control_session_volume_inc) { this.m_is_change_session_volume_inc=true; event_id=SYMBOL_EVENT_SESSION_VOLUME_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_volume_value,this.Name())) this.m_struct_prev_symbol.session_volume=this.m_struct_curr_symbol.session_volume; } else if(this.m_changed_session_volume_value<-this.m_control_session_volume_dec) { this.m_is_change_session_volume_dec=true; event_id=SYMBOL_EVENT_SESSION_VOLUME_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_volume_value,this.Name())) this.m_struct_prev_symbol.session_volume=this.m_struct_curr_symbol.session_volume; } } //--- Change of the total turnover during the current session if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_TURNOVER)) { this.m_changed_session_turnover_value=this.m_struct_curr_symbol.session_turnover-this.m_struct_prev_symbol.session_turnover; if(this.m_changed_session_turnover_value>this.m_control_session_turnover_inc) { this.m_is_change_session_turnover_inc=true; event_id=SYMBOL_EVENT_SESSION_TURNOVER_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_turnover_value,this.Name())) this.m_struct_prev_symbol.session_turnover=this.m_struct_curr_symbol.session_turnover; } else if(this.m_changed_session_turnover_value<-this.m_control_session_turnover_dec) { this.m_is_change_session_turnover_dec=true; event_id=SYMBOL_EVENT_SESSION_TURNOVER_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_turnover_value,this.Name())) this.m_struct_prev_symbol.session_turnover=this.m_struct_curr_symbol.session_turnover; } } //--- Change of the total volume of open positions during the current session if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_INTEREST)) { this.m_changed_session_interest_value=this.m_struct_curr_symbol.session_interest-this.m_struct_prev_symbol.session_interest; if(this.m_changed_session_interest_value>this.m_control_session_interest_inc) { this.m_is_change_session_interest_inc=true; event_id=SYMBOL_EVENT_SESSION_INTEREST_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_interest_value,this.Name())) this.m_struct_prev_symbol.session_interest=this.m_struct_curr_symbol.session_interest; } else if(this.m_changed_session_interest_value<-this.m_control_session_interest_dec) { this.m_is_change_session_interest_dec=true; event_id=SYMBOL_EVENT_SESSION_INTEREST_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_interest_value,this.Name())) this.m_struct_prev_symbol.session_interest=this.m_struct_curr_symbol.session_interest; } } //--- Change of the current total volume of buy orders if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_BUY_ORD_VOLUME)) { this.m_changed_session_buy_ord_volume_value=this.m_struct_curr_symbol.session_buy_ord_volume-this.m_struct_prev_symbol.session_buy_ord_volume; if(this.m_changed_session_buy_ord_volume_value>this.m_control_session_buy_ord_volume_inc) { this.m_is_change_session_buy_ord_volume_inc=true; event_id=SYMBOL_EVENT_SESSION_BUY_ORD_VOLUME_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_buy_ord_volume_value,this.Name())) this.m_struct_prev_symbol.session_buy_ord_volume=this.m_struct_curr_symbol.session_buy_ord_volume; } else if(this.m_changed_session_buy_ord_volume_value<-this.m_control_session_buy_ord_volume_dec) { this.m_is_change_session_buy_ord_volume_dec=true; event_id=SYMBOL_EVENT_SESSION_BUY_ORD_VOLUME_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_buy_ord_volume_value,this.Name())) this.m_struct_prev_symbol.session_buy_ord_volume=this.m_struct_curr_symbol.session_buy_ord_volume; } } //--- Change of the current total volume of sell orders if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_SELL_ORD_VOLUME)) { this.m_changed_session_sell_ord_volume_value=this.m_struct_curr_symbol.session_sell_ord_volume-this.m_struct_prev_symbol.session_sell_ord_volume; if(this.m_changed_session_sell_ord_volume_value>this.m_control_session_sell_ord_volume_inc) { this.m_is_change_session_sell_ord_volume_inc=true; event_id=SYMBOL_EVENT_SESSION_SELL_ORD_VOLUME_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_sell_ord_volume_value,this.Name())) this.m_struct_prev_symbol.session_sell_ord_volume=this.m_struct_curr_symbol.session_sell_ord_volume; } else if(this.m_changed_session_sell_ord_volume_value<-this.m_control_session_sell_ord_volume_dec) { this.m_is_change_session_sell_ord_volume_dec=true; event_id=SYMBOL_EVENT_SESSION_SELL_ORD_VOLUME_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_sell_ord_volume_value,this.Name())) this.m_struct_prev_symbol.session_sell_ord_volume=this.m_struct_curr_symbol.session_sell_ord_volume; } } //--- Session open price change if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_OPEN)) { this.m_changed_session_open_value=this.m_struct_curr_symbol.session_open-this.m_struct_prev_symbol.session_open; if(this.m_changed_session_open_value>this.m_control_session_open_inc) { this.m_is_change_session_open_inc=true; event_id=SYMBOL_EVENT_SESSION_OPEN_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_open_value,this.Name())) this.m_struct_prev_symbol.session_open=this.m_struct_curr_symbol.session_open; } else if(this.m_changed_session_open_value<-this.m_control_session_open_dec) { this.m_is_change_session_open_dec=true; event_id=SYMBOL_EVENT_SESSION_OPEN_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_open_value,this.Name())) this.m_struct_prev_symbol.session_open=this.m_struct_curr_symbol.session_open; } } //--- Session close price change if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_CLOSE)) { this.m_changed_session_close_value=this.m_struct_curr_symbol.session_close-this.m_struct_prev_symbol.session_close; if(this.m_changed_session_close_value>this.m_control_session_close_inc) { this.m_is_change_session_close_inc=true; event_id=SYMBOL_EVENT_SESSION_CLOSE_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_close_value,this.Name())) this.m_struct_prev_symbol.session_close=this.m_struct_curr_symbol.session_close; } else if(this.m_changed_session_close_value<-this.m_control_session_close_dec) { this.m_is_change_session_close_dec=true; event_id=SYMBOL_EVENT_SESSION_CLOSE_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_close_value,this.Name())) this.m_struct_prev_symbol.session_close=this.m_struct_curr_symbol.session_close; } } //--- Average weighted session price change if(this.IsPresentEventFlag(SYMBOL_EVENT_FLAG_SESSION_AW)) { this.m_changed_session_aw_value=this.m_struct_curr_symbol.session_aw-this.m_struct_prev_symbol.session_aw; if(this.m_changed_session_aw_value>this.m_control_session_aw_inc) { this.m_is_change_session_aw_inc=true; event_id=SYMBOL_EVENT_SESSION_AW_INC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_aw_value,this.Name())) this.m_struct_prev_symbol.session_aw=this.m_struct_curr_symbol.session_aw; } else if(this.m_changed_session_aw_value<-this.m_control_session_aw_dec) { this.m_is_change_session_aw_dec=true; event_id=SYMBOL_EVENT_SESSION_AW_DEC; if(this.EventAdd(event_id,this.TickTime(),this.m_changed_session_aw_value,this.Name())) this.m_struct_prev_symbol.session_aw=this.m_struct_curr_symbol.session_aw; } } } //+------------------------------------------------------------------+
El método es bastante voluminoso, pero solo debido a los bloques de comprobaciones idénticas del cambio en las propiedades del símbolo investigadas. Ya analizamos un método análogo en la parte 13, al monitorear los cambios de la cuenta. Aquí la lógica es similar, salvo que ahora toda nuestra funcionalidad de guardado de eventos se ubica en el objeto básico CBaseObj.
Vamos a usar como ejemplo el cambio del precio medio ponderado de la sesión.
Al inicio del método, reseteamos los valores de las propiedades investigadas con la ayuda del método InitChangesParams() y establecemos el estado del evento como "No hay eventos".
- Con la ayuda del método IsPresentEventFlag(), también ubicado en el objeto básico, comprobamos la presencia de la bandera de cambio de valor SYMBOL_SESSION_AW del símbolo en el código del evento registrado en la varible m_event_code.
Si la bandera de cambio del valor comprobado existe en el código del evento, - calculamos la magnitud del cambio de esta propiedad y comprobamos si este valor ha superado el valor de control.
- Si el valor calculado es superior al valor controlado,
- establecemos la bandera de evento de aumento del precio medio ponderado,
- registramos en el identificador de evento "Evento de aumento del precio medio ponderado" y
- llamamos al método de adición de un evento a la lista EventAdd() de la clase básica CBaseObj.
Si hemos añadido con éxito el evento a la lista, - guardamos el valor actual de la propiedad como pasado, para su posterior comprobación.
Enviamos al método de adición de un evento a la lista EventAdd() los siguientes datos:
- el identificador del evento (event_id, rellenado al comprobar el evento)
- la hora actual en milisegundos (método TickTime() de la clase básica CBaseObj)
- el valor calculado en el que ha cambiado la propiedad del símbolo (m_changed_session_aw_value)
- el nombre del objeto (en este caso, el nombre del símbolo)
En el constructor protegido de la clase, introducimos igualmente un pequeño cambio: para rellenar la nueva propiedad del objeto de símbolo "índice del símbolo en la ventana de Observación de mercado", deberemos transmitir este índice al escanear los símbolos en la observación de mercado. Transmitiremos el índice directamente al constructor de clase:
protected: //--- Protected parametric constructor CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name,const int index);
Asimismo, añadimos en la sección protegida de la clase un método más, encargado de retornar el número de dígitos tras la coma según el método de cálculo de los swaps:
//--- Get and return integer properties of a selected symbol from its parameters bool SymbolExists(const string name) const; long SymbolExists(void) const; long SymbolCustom(void) const; long SymbolChartMode(void) const; long SymbolMarginHedgedUseLEG(void) const; long SymbolOrderFillingMode(void) const; long SymbolOrderMode(void) const; long SymbolExpirationMode(void) const; long SymbolOrderGTCMode(void) const; long SymbolOptionMode(void) const; long SymbolOptionRight(void) const; long SymbolBackgroundColor(void) const; long SymbolCalcMode(void) const; long SymbolSwapMode(void) const; long SymbolDigitsLot(void); int SymbolDigitsBySwap(void); //--- Get and return real properties of a selected symbol from its parameters
Lo que ocurre es que los swaps se pueden calcular en dinero, puntos y tanto por ciento. Y para cada uno de estos tipos de cálculo de swap, resulta imprescindible retornar el valor correspondiente del número de dígitos tras la coma. Este método precisamente los retorna. Vamos a escribirlo fuera del cuerpo de la clase:
//+------------------------------------------------------------------+ //| Return the number of decimal places | //| depending on the swap calculation method | //+------------------------------------------------------------------+ int CSymbol::SymbolDigitsBySwap(void) { return ( this.SwapMode()==SYMBOL_SWAP_MODE_POINTS || this.SwapMode()==SYMBOL_SWAP_MODE_REOPEN_CURRENT || this.SwapMode()==SYMBOL_SWAP_MODE_REOPEN_BID ? this.Digits() : this.SwapMode()==SYMBOL_SWAP_MODE_CURRENCY_SYMBOL || this.SwapMode()==SYMBOL_SWAP_MODE_CURRENCY_MARGIN || this.SwapMode()==SYMBOL_SWAP_MODE_CURRENCY_DEPOSIT ? this.DigitsCurrency(): this.SwapMode()==SYMBOL_SWAP_MODE_INTEREST_CURRENT || this.SwapMode()==SYMBOL_SWAP_MODE_INTEREST_OPEN ? 1 : 0 ); } //+------------------------------------------------------------------+
Hacemos el método Refresh() virtual, dado que ha sido definido así en la clase básica de todos los objetos CBaseObj. Asimismo, cambiaremos el tipo de método de actualización de los datos de cotización RefreshRates() de void a bool, dado que ahora, al inicio del método Refresh() se llamará el método RefreshRates(), y si no hemos logrado obtener los datos en él, el método retornará false, por lo que también se realizará de inmediato la salida del método Refresh().
Además, añadimos la definición del método que retorna la descripción del evento de símbolo:
//--- Update all symbol data virtual void Refresh(void); //--- Update quote data by a symbol bool RefreshRates(void); //--- Return description of symbol events string EventDescription(const ENUM_SYMBOL_EVENT event);
en la sección pública de la clase, en el apartado de los métodos de acceso simplificado, en los métodos que retornan las propiedades de tipo entero del símbolo,
añadimos el método de retorno del índice del símbolo en la venta de "Observación de mercado":
//+------------------------------------------------------------------+ //| Methods of a simplified access to the order object properties | //+------------------------------------------------------------------+ //--- Integer properties long Status(void) const { return this.GetProperty(SYMBOL_PROP_STATUS); } int IndexInMarketWatch(void) const { return (int)this.GetProperty(SYMBOL_PROP_INDEX_MW); } bool IsCustom(void) const { return (bool)this.GetProperty(SYMBOL_PROP_CUSTOM); } color ColorBackground(void) const { return (color)this.GetProperty(SYMBOL_PROP_BACKGROUND_COLOR); } ENUM_SYMBOL_CHART_MODE ChartMode(void) const { return (ENUM_SYMBOL_CHART_MODE)this.GetProperty(SYMBOL_PROP_CHART_MODE); } bool IsExist(void) const { return (bool)this.GetProperty(SYMBOL_PROP_EXIST); } bool IsExist(const string name) const { return this.SymbolExists(name); } bool IsSelect(void) const { return (bool)this.GetProperty(SYMBOL_PROP_SELECT); } bool IsVisible(void) const { return (bool)this.GetProperty(SYMBOL_PROP_VISIBLE); } long SessionDeals(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_DEALS); } long SessionBuyOrders(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_BUY_ORDERS); } long SessionSellOrders(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_SELL_ORDERS); } long Volume(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME); } long VolumeHigh(void) const { return this.GetProperty(SYMBOL_PROP_VOLUMEHIGH); } long VolumeLow(void) const { return this.GetProperty(SYMBOL_PROP_VOLUMELOW); } datetime Time(void) const { return (datetime)this.GetProperty(SYMBOL_PROP_TIME); } int Digits(void) const { return (int)this.GetProperty(SYMBOL_PROP_DIGITS); } int DigitsLot(void) const { return (int)this.GetProperty(SYMBOL_PROP_DIGITS_LOTS); } int Spread(void) const { return (int)this.GetProperty(SYMBOL_PROP_SPREAD); } bool IsSpreadFloat(void) const { return (bool)this.GetProperty(SYMBOL_PROP_SPREAD_FLOAT); } int TicksBookdepth(void) const { return (int)this.GetProperty(SYMBOL_PROP_TICKS_BOOKDEPTH); } ENUM_SYMBOL_CALC_MODE TradeCalcMode(void) const { return (ENUM_SYMBOL_CALC_MODE)this.GetProperty(SYMBOL_PROP_TRADE_CALC_MODE); } ENUM_SYMBOL_TRADE_MODE TradeMode(void) const { return (ENUM_SYMBOL_TRADE_MODE)this.GetProperty(SYMBOL_PROP_TRADE_MODE); } datetime StartTime(void) const { return (datetime)this.GetProperty(SYMBOL_PROP_START_TIME); } datetime ExpirationTime(void) const { return (datetime)this.GetProperty(SYMBOL_PROP_EXPIRATION_TIME); } int TradeStopLevel(void) const { return (int)this.GetProperty(SYMBOL_PROP_TRADE_STOPS_LEVEL); } int TradeFreezeLevel(void) const { return (int)this.GetProperty(SYMBOL_PROP_TRADE_FREEZE_LEVEL); } ENUM_SYMBOL_TRADE_EXECUTION TradeExecutionMode(void) const { return (ENUM_SYMBOL_TRADE_EXECUTION)this.GetProperty(SYMBOL_PROP_TRADE_EXEMODE); } ENUM_SYMBOL_SWAP_MODE SwapMode(void) const { return (ENUM_SYMBOL_SWAP_MODE)this.GetProperty(SYMBOL_PROP_SWAP_MODE); } ENUM_DAY_OF_WEEK SwapRollover3Days(void) const { return (ENUM_DAY_OF_WEEK)this.GetProperty(SYMBOL_PROP_SWAP_ROLLOVER3DAYS); } bool IsMarginHedgedUseLeg(void) const { return (bool)this.GetProperty(SYMBOL_PROP_MARGIN_HEDGED_USE_LEG); } int ExpirationModeFlags(void) const { return (int)this.GetProperty(SYMBOL_PROP_EXPIRATION_MODE); } int FillingModeFlags(void) const { return (int)this.GetProperty(SYMBOL_PROP_FILLING_MODE); } int OrderModeFlags(void) const { return (int)this.GetProperty(SYMBOL_PROP_ORDER_MODE); } ENUM_SYMBOL_ORDER_GTC_MODE OrderModeGTC(void) const { return (ENUM_SYMBOL_ORDER_GTC_MODE)this.GetProperty(SYMBOL_PROP_ORDER_GTC_MODE); } ENUM_SYMBOL_OPTION_MODE OptionMode(void) const { return (ENUM_SYMBOL_OPTION_MODE)this.GetProperty(SYMBOL_PROP_OPTION_MODE); } ENUM_SYMBOL_OPTION_RIGHT OptionRight(void) const { return (ENUM_SYMBOL_OPTION_RIGHT)this.GetProperty(SYMBOL_PROP_OPTION_RIGHT); } //--- Real properties
Y en los métodos que retornan las propiedades de tipo real
añadimos el método que retorna el precio Bid o Last, el método que retorna el precio Bid o Last máximo en el día y el método que retorna el precio Bid o Last mínimo en el día:
//--- Real properties double Bid(void) const { return this.GetProperty(SYMBOL_PROP_BID); } double BidHigh(void) const { return this.GetProperty(SYMBOL_PROP_BIDHIGH); } double BidLow(void) const { return this.GetProperty(SYMBOL_PROP_BIDLOW); } double Ask(void) const { return this.GetProperty(SYMBOL_PROP_ASK); } double AskHigh(void) const { return this.GetProperty(SYMBOL_PROP_ASKHIGH); } double AskLow(void) const { return this.GetProperty(SYMBOL_PROP_ASKLOW); } double Last(void) const { return this.GetProperty(SYMBOL_PROP_LAST); } double LastHigh(void) const { return this.GetProperty(SYMBOL_PROP_LASTHIGH); } double LastLow(void) const { return this.GetProperty(SYMBOL_PROP_LASTLOW); } double VolumeReal(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_REAL); } double VolumeHighReal(void) const { return this.GetProperty(SYMBOL_PROP_VOLUMEHIGH_REAL); } double VolumeLowReal(void) const { return this.GetProperty(SYMBOL_PROP_VOLUMELOW_REAL); } double OptionStrike(void) const { return this.GetProperty(SYMBOL_PROP_OPTION_STRIKE); } double Point(void) const { return this.GetProperty(SYMBOL_PROP_POINT); } double TradeTickValue(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE); } double TradeTickValueProfit(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT); } double TradeTickValueLoss(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS); } double TradeTickSize(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_SIZE); } double TradeContractSize(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_CONTRACT_SIZE); } double TradeAccuredInterest(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_ACCRUED_INTEREST); } double TradeFaceValue(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_FACE_VALUE); } double TradeLiquidityRate(void) const { return this.GetProperty(SYMBOL_PROP_TRADE_LIQUIDITY_RATE); } double LotsMin(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_MIN); } double LotsMax(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_MAX); } double LotsStep(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_STEP); } double VolumeLimit(void) const { return this.GetProperty(SYMBOL_PROP_VOLUME_LIMIT); } double SwapLong(void) const { return this.GetProperty(SYMBOL_PROP_SWAP_LONG); } double SwapShort(void) const { return this.GetProperty(SYMBOL_PROP_SWAP_SHORT); } double MarginInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_INITIAL); } double MarginMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_MAINTENANCE); } double MarginLongInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_INITIAL); } double MarginBuyStopInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL); } double MarginBuyLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL); } double MarginBuyStopLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL); } double MarginLongMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE); } double MarginBuyStopMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE); } double MarginBuyLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE); } double MarginBuyStopLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE); } double MarginShortInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_INITIAL); } double MarginSellStopInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL); } double MarginSellLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL); } double MarginSellStopLimitInitial(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL); } double MarginShortMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE); } double MarginSellStopMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE); } double MarginSellLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE); } double MarginSellStopLimitMaintenance(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE); } double SessionVolume(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_VOLUME); } double SessionTurnover(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_TURNOVER); } double SessionInterest(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_INTEREST); } double SessionBuyOrdersVolume(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME); } double SessionSellOrdersVolume(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME); } double SessionOpen(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_OPEN); } double SessionClose(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_CLOSE); } double SessionAW(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_AW); } double SessionPriceSettlement(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT); } double SessionPriceLimitMin(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN); } double SessionPriceLimitMax(void) const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX); } double MarginHedged(void) const { return this.GetProperty(SYMBOL_PROP_MARGIN_HEDGED); } double NormalizedPrice(const double price) const; double BidLast(void) const; double BidLastHigh(void) const; double BidLastLow(void) const; //--- String properties
Los implementamos fuera del cuerpo de la clase:
//+------------------------------------------------------------------+ //| Return Bid or Last price | //| depending on the chart construction method | //+------------------------------------------------------------------+ double CSymbol::BidLast(void) const { return(this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.GetProperty(SYMBOL_PROP_BID) : this.GetProperty(SYMBOL_PROP_LAST)); } //+------------------------------------------------------------------+ //| Return maximum Bid or Last price for a day | //| depending on the chart construction method | //+------------------------------------------------------------------+ double CSymbol::BidLastHigh(void) const { return(this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.GetProperty(SYMBOL_PROP_BIDHIGH) : this.GetProperty(SYMBOL_PROP_LASTHIGH)); } //+------------------------------------------------------------------+ //| Return minimum Bid or Last price for a day | //| depending on the chart construction method | //+------------------------------------------------------------------+ double CSymbol::BidLastLow(void) const { return(this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.GetProperty(SYMBOL_PROP_BIDLOW) : this.GetProperty(SYMBOL_PROP_LASTLOW)); } //+------------------------------------------------------------------+
Aquí todo es sencillo: dependiendo de los precios sobre los que se construye el gráfico de precio, se retorna la propiedad correspondiente del símbolo, o bien con los precios Bid, o bien con los precios Last.
También en la sección pública, escribimos los métodos para esteblecer las propiedades controladas y los métodos que retornan las magnitudes de cambio de las propiedades y las banderas de evento del símbolo:
//+------------------------------------------------------------------+ //| Get and set the parameters of tracked changes | //+------------------------------------------------------------------+ //--- Execution //--- Flag of changing the trading mode for a symbol bool IsChangedTradeMode(void) const { return this.m_is_change_trade_mode; } //--- Current session deals //--- setting the controlled value of (1) growth, (2) decrease in the number of deals during the current session //--- getting (3) the number of deals change value during the current session, //--- getting the flag of the number of deals change during the current session exceeding the (4) growth, (5) decrease value void SetControlSessionDealsInc(const long value) { this.m_control_session_deals_inc=::fabs(value); } void SetControlSessionDealsDec(const long value) { this.m_control_session_deals_dec=::fabs(value); } long GetValueChangedSessionDeals(void) const { return this.m_changed_session_deals_value; } bool IsIncreaseSessionDeals(void) const { return this.m_is_change_session_deals_inc; } bool IsDecreaseSessionDeals(void) const { return this.m_is_change_session_deals_dec; } //--- Buy orders of the current session //--- setting the controlled value of (1) growth, (2) decrease in the current number of Buy orders //--- getting (3) the current number of Buy orders change value, //--- getting the flag of the current Buy orders' number change exceeding the (4) growth, (5) decrease value void SetControlSessionBuyOrdInc(const long value) { this.m_control_session_buy_ord_inc=::fabs(value); } void SetControlSessionBuyOrdDec(const long value) { this.m_control_session_buy_ord_dec=::fabs(value); } long GetValueChangedSessionBuyOrders(void) const { return this.m_changed_session_buy_ord_value; } bool IsIncreaseSessionBuyOrders(void) const { return this.m_is_change_session_buy_ord_inc; } bool IsDecreaseSessionBuyOrders(void) const { return this.m_is_change_session_buy_ord_dec; } //--- Sell orders of the current session //--- setting the controlled value of (1) growth, (2) decrease in the current number of Sell orders //--- getting (3) the current number of Sell orders change value, //--- getting the flag of the current Sell orders' number change exceeding the (4) growth, (5) decrease value void SetControlSessionSellOrdInc(const long value) { this.m_control_session_sell_ord_inc=::fabs(value); } void SetControlSessionSellOrdDec(const long value) { this.m_control_session_sell_ord_dec=::fabs(value); } long GetValueChangedSessionSellOrders(void) const { return this.m_changed_session_sell_ord_value; } bool IsIncreaseSessionSellOrders(void) const { return this.m_is_change_session_sell_ord_inc; } bool IsDecreaseSessionSellOrders(void) const { return this.m_is_change_session_sell_ord_dec; } //--- Volume of the last deal //--- setting the last deal volume controlled (1) growth, (2) decrease value //--- getting (3) volume change values in the last deal, //--- getting the flag of the volume change in the last deal exceeding the (4) growth, (5) decrease value void SetControlVolumeInc(const long value) { this.m_control_volume_inc=::fabs(value); } void SetControlVolumeDec(const long value) { this.m_control_volume_dec=::fabs(value); } long GetValueChangedVolume(void) const { return this.m_changed_volume_value; } bool IsIncreaseVolume(void) const { return this.m_is_change_volume_inc; } bool IsDecreaseVolume(void) const { return this.m_is_change_volume_dec; } //--- Maximum volume within a day //--- setting the maximum day volume controlled (1) growth, (2) decrease value //--- getting (3) the maximum volume change value within a day, //--- getting the flag of the maximum day volume change exceeding the (4) growth, (5) decrease value void SetControlVolumeHighInc(const long value) { this.m_control_volume_high_day_inc=::fabs(value); } void SetControlVolumeHighDec(const long value) { this.m_control_volume_high_day_dec=::fabs(value); } long GetValueChangedVolumeHigh(void) const { return this.m_changed_volume_high_day_value; } bool IsIncreaseVolumeHigh(void) const { return this.m_is_change_volume_high_day_inc; } bool IsDecreaseVolumeHigh(void) const { return this.m_is_change_volume_high_day_dec; } //--- Minimum volume within a day //--- setting the minimum day volume controlled (1) growth, (2) decrease value //--- getting (3) the minimum volume change value within a day, //--- getting the flag of the minimum day volume change exceeding the (4) growth, (5) decrease value void SetControlVolumeLowInc(const long value) { this.m_control_volume_low_day_inc=::fabs(value); } void SetControlVolumeLowDec(const long value) { this.m_control_volume_low_day_dec=::fabs(value); } long GetValueChangedVolumeLow(void) const { return this.m_changed_volume_low_day_value; } bool IsIncreaseVolumeLow(void) const { return this.m_is_change_volume_low_day_inc; } bool IsDecreaseVolumeLow(void) const { return this.m_is_change_volume_low_day_dec; } //--- Spread //--- setting the controlled spread decrease (1) growth, (2) decrease value in points //--- getting (3) spread change value in points, //--- getting the flag of the spread change in points exceeding the (4) growth, (5) decrease value void SetControlSpreadInc(const int value) { this.m_control_spread_inc=::fabs(value); } void SetControlSpreadDec(const int value) { this.m_control_spread_dec=::fabs(value); } int GetValueChangedSpread(void) const { return this.m_changed_spread_value; } bool IsIncreaseSpread(void) const { return this.m_is_change_spread_inc; } bool IsDecreaseSpread(void) const { return this.m_is_change_spread_dec; } //--- StopLevel //--- setting the controlled StopLevel decrease (1) growth, (2) decrease value in points //--- getting (3) StopLevel change value in points, //--- getting the flag of StopLevel change in points exceeding the (4) growth, (5) decrease value void SetControlStopLevelInc(const int value) { this.m_control_stops_level_inc=::fabs(value); } void SetControlStopLevelDec(const int value) { this.m_control_stops_level_dec=::fabs(value); } int GetValueChangedStopLevel(void) const { return this.m_changed_stops_level_value; } bool IsIncreaseStopLevel(void) const { return this.m_is_change_stops_level_inc; } bool IsDecreaseStopLevel(void) const { return this.m_is_change_stops_level_dec; } //--- Freeze distance //--- setting the controlled FreezeLevel decrease (1) growth, (2) decrease value in points //--- getting (3) FreezeLevel change value in points, //--- getting the flag of FreezeLevel change in points exceeding the (4) growth, (5) decrease value void SetControlFreezeLevelInc(const int value) { this.m_control_freeze_level_inc=::fabs(value); } void SetControlFreezeLevelDec(const int value) { this.m_control_freeze_level_dec=::fabs(value); } int GetValueChangedFreezeLevel(void) const { return this.m_changed_freeze_level_value; } bool IsIncreaseFreezeLevel(void) const { return this.m_is_change_freeze_level_inc; } bool IsDecreaseFreezeLevel(void) const { return this.m_is_change_freeze_level_dec; } //--- Bid/Last //--- setting the Bid or Last price controlled (1) growth, (2) decrease value //--- getting (3) Bid or Last price change value, //--- getting the flag of the Bid or Last price change exceeding the (4) growth, (5) decrease value void SetControlBidLastInc(const double value) { this.m_control_bid_last_inc=::fabs(value); } void SetControlBidLastDec(const double value) { this.m_control_bid_last_dec=::fabs(value); } double GetValueChangedBidLast(void) const { return this.m_changed_bid_last_value; } bool IsIncreaseBidLast(void) const { return this.m_is_change_bid_last_inc; } bool IsDecreaseBidLast(void) const { return this.m_is_change_bid_last_dec; } //--- Maximum Bid/Last of the day //--- setting the maximum Bid or Last price controlled (1) growth, (2) decrease value //--- getting the (3) maximum Bid or Last price change value, //--- getting the flag of the maximum Bid or Last price change exceeding the (4) growth, (5) decrease value void SetControlBidLastHighInc(const double value) { this.m_control_bid_last_high_inc=::fabs(value); } void SetControlBidLastHighDec(const double value) { this.m_control_bid_last_high_dec=::fabs(value); } double GetValueChangedBidLastHigh(void) const { return this.m_changed_bid_last_high_value; } bool IsIncreaseBidLastHigh(void) const { return this.m_is_change_bid_last_high_inc; } bool IsDecreaseBidLastHigh(void) const { return this.m_is_change_bid_last_high_dec; } //--- Minimum Bid/Last of the day //--- setting the minimum Bid or Last price controlled (1) growth, (2) decrease value //--- getting the (3) minimum Bid or Last price change value, //--- getting the flag of the minimum Bid or Last price change exceeding the (4) growth, (5) decrease value void SetControlBidLastLowInc(const double value) { this.m_control_bid_last_low_inc=::fabs(value); } void SetControlBidLastLowDec(const double value) { this.m_control_bid_last_low_dec=::fabs(value); } double GetValueChangedBidLastLow(void) const { return this.m_changed_bid_last_low_value; } bool IsIncreaseBidLastLow(void) const { return this.m_is_change_bid_last_low_inc; } bool IsDecreaseBidLastLow(void) const { return this.m_is_change_bid_last_low_dec; } //--- Ask //--- setting the Ask price controlled (1) growth, (2) decrease value //--- getting (3) Ask price change value, //--- getting the flag of the Ask price change exceeding the (4) growth, (5) decrease value void SetControlAskInc(const double value) { this.m_control_ask_inc=::fabs(value); } void SetControlAskDec(const double value) { this.m_control_ask_dec=::fabs(value); } double GetValueChangedAsk(void) const { return this.m_changed_ask_value; } bool IsIncreaseAsk(void) const { return this.m_is_change_ask_inc; } bool IsDecreaseAsk(void) const { return this.m_is_change_ask_dec; } //--- Maximum Ask price for the day //--- setting the maximum day Ask controlled (1) growth, (2) decrease value //--- getting (3) the maximum Ask change value within a day, //--- getting the flag of the maximum day Ask change exceeding the (4) growth, (5) decrease value void SetControlAskHighInc(const double value) { this.m_control_ask_high_inc=::fabs(value); } void SetControlAskHighDec(const double value) { this.m_control_ask_high_dec=::fabs(value); } double GetValueChangedAskHigh(void) const { return this.m_changed_ask_high_value; } bool IsIncreaseAskHigh(void) const { return this.m_is_change_ask_high_inc; } bool IsDecreaseAskHigh(void) const { return this.m_is_change_ask_high_dec; } //--- Minimum Ask price for the day //--- setting the minimum day Ask controlled (1) growth, (2) decrease value //--- getting (3) the minimum Ask change value within a day, //--- getting the flag of the minimum day Ask change exceeding the (4) growth, (5) decrease value void SetControlAskLowInc(const double value) { this.m_control_ask_low_inc=::fabs(value); } void SetControlAskLowDec(const double value) { this.m_control_ask_low_dec=::fabs(value); } double GetValueChangedAskLow(void) const { return this.m_changed_ask_low_value; } bool IsIncreaseAskLow(void) const { return this.m_is_change_ask_low_inc; } bool IsDecreaseAskLow(void) const { return this.m_is_change_ask_low_dec; } //--- Real Volume for the day //--- setting the real day volume controlled (1) growth, (2) decrease value //--- getting (3) the change value of the real day volume, //--- getting the flag of the real day volume change exceeding the (4) growth, (5) decrease value void SetControlVolumeRealInc(const double value) { this.m_control_volume_real_inc=::fabs(value); } void SetControlVolumeRealDec(const double value) { this.m_control_volume_real_dec=::fabs(value); } double GetValueChangedVolumeReal(void) const { return this.m_changed_volume_real_value; } bool IsIncreaseVolumeReal(void) const { return this.m_is_change_volume_real_inc; } bool IsDecreaseVolumeReal(void) const { return this.m_is_change_volume_real_dec; } //--- Maximum real volume for the day //--- setting the maximum real day volume controlled (1) growth, (2) decrease value //--- getting (3) the change value of the maximum real day volume, //--- getting the flag of the maximum real day volume change exceeding the (4) growth, (5) decrease value void SetControlVolumeHighRealInc(const double value) { this.m_control_volume_high_real_day_inc=::fabs(value); } void SetControlVolumeHighRealDec(const double value) { this.m_control_volume_high_real_day_dec=::fabs(value); } double GetValueChangedVolumeHighReal(void) const { return this.m_changed_volume_high_real_day_value; } bool IsIncreaseVolumeHighReal(void) const { return this.m_is_change_volume_high_real_day_inc; } bool IsDecreaseVolumeHighReal(void) const { return this.m_is_change_volume_high_real_day_dec; } //--- Minimum real volume for the day //--- setting the minimum real day volume controlled (1) growth, (2) decrease value //--- getting (3) the change value of the minimum real day volume, //--- getting the flag of the minimum real day volume change exceeding the (4) growth, (5) decrease value void SetControlVolumeLowRealInc(const double value) { this.m_control_volume_low_real_day_inc=::fabs(value); } void SetControlVolumeLowRealDec(const double value) { this.m_control_volume_low_real_day_dec=::fabs(value); } double GetValueChangedVolumeLowReal(void) const { return this.m_changed_volume_low_real_day_value; } bool IsIncreaseVolumeLowReal(void) const { return this.m_is_change_volume_low_real_day_inc; } bool IsDecreaseVolumeLowReal(void) const { return this.m_is_change_volume_low_real_day_dec; } //--- Strike price //--- setting the strike price controlled (1) growth, (2) decrease value //--- getting (3) the change value of the strike price, //--- getting the flag of the strike price change exceeding the (4) growth, (5) decrease value void SetControlOptionStrikeInc(const double value) { this.m_control_option_strike_inc=::fabs(value); } void SetControlOptionStrikeDec(const double value) { this.m_control_option_strike_dec=::fabs(value); } double GetValueChangedOptionStrike(void) const { return this.m_changed_option_strike_value; } bool IsIncreaseOptionStrike(void) const { return this.m_is_change_option_strike_inc; } bool IsDecreaseOptionStrike(void) const { return this.m_is_change_option_strike_dec; } //--- Maximum allowed total volume of unidirectional positions and orders //--- (1) getting the change value of the maximum allowed total volume of unidirectional positions and orders, //--- getting the flag of (2) increasing, (3) decreasing the maximum allowed total volume of unidirectional positions and orders double GetValueChangedVolumeLimit(void) const { return this.m_changed_volume_limit_value; } bool IsIncreaseVolumeLimit(void) const { return this.m_is_change_volume_limit_inc; } bool IsDecreaseVolumeLimit(void) const { return this.m_is_change_volume_limit_dec; } //--- Swap long //--- (1) getting the swap long change value, //--- getting the flag of (2) increasing, (3) decreasing the swap long double GetValueChangedSwapLong(void) const { return this.m_changed_swap_long_value; } bool IsIncreaseSwapLong(void) const { return this.m_is_change_swap_long_inc; } bool IsDecreaseSwapLong(void) const { return this.m_is_change_swap_long_dec; } //--- Swap short //--- (1) getting the swap short change value, //--- getting the flag of (2) increasing, (3) decreasing the swap short double GetValueChangedSwapShort(void) const { return this.m_changed_swap_short_value; } bool IsIncreaseSwapShort(void) const { return this.m_is_change_swap_short_inc; } bool IsDecreaseSwapShort(void) const { return this.m_is_change_swap_short_dec; } //--- The total volume of deals in the current session //--- setting the controlled value of (1) growth, (2) decrease in the total volume of deals during the current session //--- getting (3) the total deal volume change value in the current session, //--- getting the flag of the total deal volume change during the current session exceeding the (4) growth, (5) decrease value void SetControlSessionVolumeInc(const double value) { this.m_control_session_volume_inc=::fabs(value); } void SetControlSessionVolumeDec(const double value) { this.m_control_session_volume_dec=::fabs(value); } double GetValueChangedSessionVolume(void) const { return this.m_changed_session_volume_value; } bool IsIncreaseSessionVolume(void) const { return this.m_is_change_session_volume_inc; } bool IsDecreaseSessionVolume(void) const { return this.m_is_change_session_volume_dec; } //--- The total turnover in the current session //--- setting the controlled value of the turnover (1) growth, (2) decrease during the current session //--- getting (3) the total turnover change value in the current session, //--- getting the flag of the total turnover change during the current session exceeding the (4) growth, (5) decrease value void SetControlSessionTurnoverInc(const double value) { this.m_control_session_turnover_inc=::fabs(value); } void SetControlSessionTurnoverDec(const double value) { this.m_control_session_turnover_dec=::fabs(value); } double GetValueChangedSessionTurnover(void) const { return this.m_changed_session_turnover_value; } bool IsIncreaseSessionTurnover(void) const { return this.m_is_change_session_turnover_inc; } bool IsDecreaseSessionTurnover(void) const { return this.m_is_change_session_turnover_dec; } //--- The total volume of open positions //--- setting the controlled value of (1) growth, (2) decrease in the total volume of open positions during the current session //--- getting (3) the change value of the open positions total volume in the current session, //--- getting the flag of the open positions total volume change during the current session exceeding the (4) growth, (5) decrease value void SetControlSessionInterestInc(const double value) { this.m_control_session_interest_inc=::fabs(value); } void SetControlSessionInterestDec(const double value) { this.m_control_session_interest_dec=::fabs(value); } double GetValueChangedSessionInterest(void) const { return this.m_changed_session_interest_value; } bool IsIncreaseSessionInterest(void) const { return this.m_is_change_session_interest_inc; } bool IsDecreaseSessionInterest(void) const { return this.m_is_change_session_interest_dec; } //--- The total volume of Buy orders at the moment //--- setting the controlled value of (1) growth, (2) decrease in the current total buy order volume //--- getting (3) the change value of the current total buy order volume, //--- getting the flag of the current total buy orders' volume change exceeding the (4) growth, (5) decrease value void SetControlSessionBuyOrdVolumeInc(const double value) { this.m_control_session_buy_ord_volume_inc=::fabs(value); } void SetControlSessionBuyOrdVolumeDec(const double value) { this.m_control_session_buy_ord_volume_dec=::fabs(value); } double GetValueChangedSessionBuyOrdVolume(void) const { return this.m_changed_session_buy_ord_volume_value; } bool IsIncreaseSessionBuyOrdVolume(void) const { return this.m_is_change_session_buy_ord_volume_inc; } bool IsDecreaseSessionBuyOrdVolume(void) const { return this.m_is_change_session_buy_ord_volume_dec; } //--- The total volume of Sell orders at the moment //--- setting the controlled value of (1) growth, (2) decrease in the current total sell order volume //--- getting (3) the change value of the current total sell order volume, //--- getting the flag of the current total sell orders' volume change exceeding the (4) growth, (5) decrease value void SetControlSessionSellOrdVolumeInc(const double value) { this.m_control_session_sell_ord_volume_inc=::fabs(value); } void SetControlSessionSellOrdVolumeDec(const double value) { this.m_control_session_sell_ord_volume_dec=::fabs(value); } double GetValueChangedSessionSellOrdVolume(void) const { return this.m_changed_session_sell_ord_volume_value; } bool IsIncreaseSessionSellOrdVolume(void) const { return this.m_is_change_session_sell_ord_volume_inc; } bool IsDecreaseSessionSellOrdVolume(void) const { return this.m_is_change_session_sell_ord_volume_dec; } //--- Session open price //--- setting the session open price controlled (1) growth, (2) decrease value //--- getting (3) the change value of the session open price, //--- getting the flag of the session open price change exceeding the (4) growth, (5) decrease value void SetControlSessionPriceOpenInc(const double value) { this.m_control_session_open_inc=::fabs(value); } void SetControlSessionPriceOpenDec(const double value) { this.m_control_session_open_dec=::fabs(value); } double GetValueChangedSessionPriceOpen(void) const { return this.m_changed_session_open_value; } bool IsIncreaseSessionPriceOpen(void) const { return this.m_is_change_session_open_inc; } bool IsDecreaseSessionPriceOpen(void) const { return this.m_is_change_session_open_dec; } //--- Session close price //--- setting the session close price controlled (1) growth, (2) decrease value //--- getting (3) the change value of the session close price, //--- getting the flag of the session close price change exceeding the (4) growth, (5) decrease value void SetControlSessionPriceCloseInc(const double value) { this.m_control_session_close_inc=::fabs(value); } void SetControlSessionPriceCloseDec(const double value) { this.m_control_session_close_dec=::fabs(value); } double GetValueChangedSessionPriceClose(void) const { return this.m_changed_session_close_value; } bool IsIncreaseSessionPriceClose(void) const { return this.m_is_change_session_close_inc; } bool IsDecreaseSessionPriceClose(void) const { return this.m_is_change_session_close_dec; } //--- The average weighted session price //--- setting the average weighted session price controlled (1) growth, (2) decrease value //--- getting (3) the change value of the average weighted session price, //--- getting the flag of the average weighted session price change exceeding the (4) growth, (5) decrease value void SetControlSessionPriceAWInc(const double value) { this.m_control_session_aw_inc=::fabs(value); } void SetControlSessionPriceAWDec(const double value) { this.m_control_session_aw_dec=::fabs(value); } double GetValueChangedSessionPriceAW(void) const { return this.m_changed_session_aw_value; } bool IsIncreaseSessionPriceAW(void) const { return this.m_is_change_session_aw_inc; } bool IsDecreaseSessionPriceAW(void) const { return this.m_is_change_session_aw_dec; } //---
Aquí: para cada una de las propiedades controladas existen métodos para establecer la magnitud controlada del cambio de propiedad, superada la cual se formará un evento cuya bandera se puede obtener con la ayuda del método que retorna la bandera de evento, mientras que la magnitud del cambio se obtiene con la ayuda del método que retorna esta magnitud. Ya hemos analizado métodos similares al implementar el seguimiento de los eventos de cuenta en la parte 13 de la descripción de la biblioteca.
Hemos introducido algunos cambios en el constructor de clase:
//+------------------------------------------------------------------+ //| Closed parametric constructor | //+------------------------------------------------------------------+ CSymbol::CSymbol(ENUM_SYMBOL_STATUS symbol_status,const string name,const int index) { this.m_name=name; if(!this.Exist()) { ::Print(DFUN_ERR_LINE,"\"",this.m_name,"\"",": ",TextByLanguage("Ошибка. Такого символа нет на сервере","Error. There is no such symbol on the server")); this.m_global_error=ERR_MARKET_UNKNOWN_SYMBOL; } bool select=::SymbolInfoInteger(this.m_name,SYMBOL_SELECT); ::ResetLastError(); if(!select) { if(!this.SetToMarketWatch()) { this.m_global_error=::GetLastError(); ::Print(DFUN_ERR_LINE,"\"",this.m_name,"\": ",TextByLanguage("Не удалось поместить в обзор рынка. Ошибка: ","Failed to put in the market watch. Error: "),this.m_global_error); } } ::ResetLastError(); if(!::SymbolInfoTick(this.m_name,this.m_tick)) { this.m_global_error=::GetLastError(); ::Print(DFUN_ERR_LINE,"\"",this.m_name,"\": ",TextByLanguage("Не удалось получить текущие цены. Ошибка: ","Could not get current prices. Error: "),this.m_global_error); } //--- Initialize data this.Reset(); this.InitMarginRates(); ::ZeroMemory(this.m_struct_prev_symbol); this.m_struct_prev_symbol.trade_mode=WRONG_VALUE; this.InitChangesParams(); this.InitControlsParams(); #ifdef __MQL5__ ::ResetLastError(); if(!this.MarginRates()) { this.m_global_error=::GetLastError(); ::Print(DFUN_ERR_LINE,this.Name(),": ",TextByLanguage("Не удалось получить коэффициенты взимания маржи. Ошибка: ","Failed to get margin rates. Error: "),this.m_global_error); return; } #endif //--- Save integer properties this.m_long_prop[SYMBOL_PROP_STATUS] = symbol_status; this.m_long_prop[SYMBOL_PROP_INDEX_MW] = index; this.m_long_prop[SYMBOL_PROP_VOLUME] = (long)this.m_tick.volume; this.m_long_prop[SYMBOL_PROP_SELECT] = ::SymbolInfoInteger(this.m_name,SYMBOL_SELECT); this.m_long_prop[SYMBOL_PROP_VISIBLE] = ::SymbolInfoInteger(this.m_name,SYMBOL_VISIBLE); this.m_long_prop[SYMBOL_PROP_SESSION_DEALS] = ::SymbolInfoInteger(this.m_name,SYMBOL_SESSION_DEALS); this.m_long_prop[SYMBOL_PROP_SESSION_BUY_ORDERS] = ::SymbolInfoInteger(this.m_name,SYMBOL_SESSION_BUY_ORDERS); this.m_long_prop[SYMBOL_PROP_SESSION_SELL_ORDERS] = ::SymbolInfoInteger(this.m_name,SYMBOL_SESSION_SELL_ORDERS); this.m_long_prop[SYMBOL_PROP_VOLUMEHIGH] = ::SymbolInfoInteger(this.m_name,SYMBOL_VOLUMEHIGH); this.m_long_prop[SYMBOL_PROP_VOLUMELOW] = ::SymbolInfoInteger(this.m_name,SYMBOL_VOLUMELOW); this.m_long_prop[SYMBOL_PROP_DIGITS] = ::SymbolInfoInteger(this.m_name,SYMBOL_DIGITS); this.m_long_prop[SYMBOL_PROP_SPREAD] = ::SymbolInfoInteger(this.m_name,SYMBOL_SPREAD); this.m_long_prop[SYMBOL_PROP_SPREAD_FLOAT] = ::SymbolInfoInteger(this.m_name,SYMBOL_SPREAD_FLOAT); this.m_long_prop[SYMBOL_PROP_TICKS_BOOKDEPTH] = ::SymbolInfoInteger(this.m_name,SYMBOL_TICKS_BOOKDEPTH); this.m_long_prop[SYMBOL_PROP_TRADE_MODE] = ::SymbolInfoInteger(this.m_name,SYMBOL_TRADE_MODE); this.m_long_prop[SYMBOL_PROP_START_TIME] = ::SymbolInfoInteger(this.m_name,SYMBOL_START_TIME); this.m_long_prop[SYMBOL_PROP_EXPIRATION_TIME] = ::SymbolInfoInteger(this.m_name,SYMBOL_EXPIRATION_TIME); this.m_long_prop[SYMBOL_PROP_TRADE_STOPS_LEVEL] = ::SymbolInfoInteger(this.m_name,SYMBOL_TRADE_STOPS_LEVEL); this.m_long_prop[SYMBOL_PROP_TRADE_FREEZE_LEVEL] = ::SymbolInfoInteger(this.m_name,SYMBOL_TRADE_FREEZE_LEVEL); this.m_long_prop[SYMBOL_PROP_TRADE_EXEMODE] = ::SymbolInfoInteger(this.m_name,SYMBOL_TRADE_EXEMODE); this.m_long_prop[SYMBOL_PROP_SWAP_ROLLOVER3DAYS] = ::SymbolInfoInteger(this.m_name,SYMBOL_SWAP_ROLLOVER3DAYS); this.m_long_prop[SYMBOL_PROP_TIME] = this.TickTime(); this.m_long_prop[SYMBOL_PROP_EXIST] = this.SymbolExists(); this.m_long_prop[SYMBOL_PROP_CUSTOM] = this.SymbolCustom(); this.m_long_prop[SYMBOL_PROP_MARGIN_HEDGED_USE_LEG] = this.SymbolMarginHedgedUseLEG(); this.m_long_prop[SYMBOL_PROP_ORDER_MODE] = this.SymbolOrderMode(); this.m_long_prop[SYMBOL_PROP_FILLING_MODE] = this.SymbolOrderFillingMode(); this.m_long_prop[SYMBOL_PROP_EXPIRATION_MODE] = this.SymbolExpirationMode(); this.m_long_prop[SYMBOL_PROP_ORDER_GTC_MODE] = this.SymbolOrderGTCMode(); this.m_long_prop[SYMBOL_PROP_OPTION_MODE] = this.SymbolOptionMode(); this.m_long_prop[SYMBOL_PROP_OPTION_RIGHT] = this.SymbolOptionRight(); this.m_long_prop[SYMBOL_PROP_BACKGROUND_COLOR] = this.SymbolBackgroundColor(); this.m_long_prop[SYMBOL_PROP_CHART_MODE] = this.SymbolChartMode(); this.m_long_prop[SYMBOL_PROP_TRADE_CALC_MODE] = this.SymbolCalcMode(); this.m_long_prop[SYMBOL_PROP_SWAP_MODE] = this.SymbolSwapMode(); //--- Save real properties this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKHIGH)] = ::SymbolInfoDouble(this.m_name,SYMBOL_ASKHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKLOW)] = ::SymbolInfoDouble(this.m_name,SYMBOL_ASKLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTHIGH)] = ::SymbolInfoDouble(this.m_name,SYMBOL_LASTHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTLOW)] = ::SymbolInfoDouble(this.m_name,SYMBOL_LASTLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_POINT)] = ::SymbolInfoDouble(this.m_name,SYMBOL_POINT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_VALUE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_VALUE_PROFIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_VALUE_LOSS); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_SIZE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_SIZE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_CONTRACT_SIZE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_CONTRACT_SIZE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MIN)] = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_MIN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MAX)] = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_MAX); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_STEP)] = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_STEP); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_LIMIT)] = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_LIMIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_LONG)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_LONG); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_SHORT)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_SHORT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_INITIAL)] = ::SymbolInfoDouble(this.m_name,SYMBOL_MARGIN_INITIAL); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_MAINTENANCE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_MARGIN_MAINTENANCE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_VOLUME)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_TURNOVER)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_TURNOVER); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_INTEREST)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_INTEREST); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_BUY_ORDERS_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_SELL_ORDERS_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_OPEN)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_OPEN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_CLOSE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_CLOSE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_AW)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_AW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_PRICE_SETTLEMENT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_PRICE_LIMIT_MIN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_PRICE_LIMIT_MAX); this.m_double_prop[this.IndexProp(SYMBOL_PROP_BID)] = this.m_tick.bid; this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASK)] = this.m_tick.ask; this.m_double_prop[this.IndexProp(SYMBOL_PROP_LAST)] = this.m_tick.last; this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDHIGH)] = this.SymbolBidHigh(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDLOW)] = this.SymbolBidLow(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_REAL)] = this.SymbolVolumeReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMEHIGH_REAL)] = this.SymbolVolumeHighReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMELOW_REAL)] = this.SymbolVolumeLowReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_OPTION_STRIKE)] = this.SymbolOptionStrike(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_ACCRUED_INTEREST)] = this.SymbolTradeAccruedInterest(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_FACE_VALUE)] = this.SymbolTradeFaceValue(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_LIQUIDITY_RATE)] = this.SymbolTradeLiquidityRate(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_HEDGED)] = this.SymbolMarginHedged(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_INITIAL)] = this.m_margin_rate.Long.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL)] = this.m_margin_rate.BuyStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL)] = this.m_margin_rate.BuyLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL)] = this.m_margin_rate.BuyStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE)] = this.m_margin_rate.Long.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE)] = this.m_margin_rate.BuyStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE)] = this.m_margin_rate.BuyLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE)] = this.m_margin_rate.BuyStopLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_INITIAL)] = this.m_margin_rate.Short.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL)] = this.m_margin_rate.SellStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL)] = this.m_margin_rate.SellLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL)] = this.m_margin_rate.SellStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE)] = this.m_margin_rate.Short.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE)] = this.m_margin_rate.SellStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE)] = this.m_margin_rate.SellLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE)]= this.m_margin_rate.SellStopLimit.Maintenance; //--- Save string properties this.m_string_prop[this.IndexProp(SYMBOL_PROP_NAME)] = this.m_name; this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_BASE)] = ::SymbolInfoString(this.m_name,SYMBOL_CURRENCY_BASE); this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_PROFIT)] = ::SymbolInfoString(this.m_name,SYMBOL_CURRENCY_PROFIT); this.m_string_prop[this.IndexProp(SYMBOL_PROP_CURRENCY_MARGIN)] = ::SymbolInfoString(this.m_name,SYMBOL_CURRENCY_MARGIN); this.m_string_prop[this.IndexProp(SYMBOL_PROP_DESCRIPTION)] = ::SymbolInfoString(this.m_name,SYMBOL_DESCRIPTION); this.m_string_prop[this.IndexProp(SYMBOL_PROP_PATH)] = ::SymbolInfoString(this.m_name,SYMBOL_PATH); this.m_string_prop[this.IndexProp(SYMBOL_PROP_BASIS)] = this.SymbolBasis(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_BANK)] = this.SymbolBank(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_ISIN)] = this.SymbolISIN(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_FORMULA)] = this.SymbolFormula(); this.m_string_prop[this.IndexProp(SYMBOL_PROP_PAGE)] = this.SymbolPage(); //--- Save additional integer properties this.m_long_prop[SYMBOL_PROP_DIGITS_LOTS] = this.SymbolDigitsLot(); //--- if(!select) this.RemoveFromMarketWatch(); } //+------------------------------------------------------------------+
Ahora, al constructor de clase se le transmite el índice del símbolo en la ventana de "Observación de mercado", se asigna el nombre del símbolo a la denominación del objeto, se resetea la estructura de los datos pasados del símbolo y se registra en el campo de la estructura de los datos pasados del símbolo trade_mode el valor WRONG_VALUE. Determinaremos el primer inicio en función de la presencia o ausencia de este valor en el campo de modo de comercio del símbolo; despues inicializaremos las variables de las propiedades modificadas y controladas del símbolo, y en la propiedad del símbolo "índice en la ventana de Observación de mercado", registraremos el índice transmitido al constructor.
Dado que tenemos la variable m_name en la clase básica CBaseObj, en la que registraremos la denomiación del objeto (en este caso, el nombre del símbolo), será necesario eliminar de la clase CSymbol la variable m_symbol_name, y cambiar todas sus entradas por m_name (en nuestro caso, la asignación del nombre del símbolo se ejecuta en el constructor de la clase).
Seleccionamos cualquiera de las entradas del texto " this.m_symbol_name" en el listado de la clase CSymbol y pulsamos la combinación de teclas Ctrl+H. Se abrirá la ventana de búsqueda y sustitución, en cuyo campo de valor buscado se encontrará ya la entrada introducida por nosotros en el texto. En el campo de edición, introducimos this.m_name y sustituimos en el listado todas las entradas encontradas this.m_symbol_name por this.m_name.
Asimismo, debemos eliminar el resto de variables de miembros de clase, que ahora se encuentran en el objeto básico CBaseObj. Su entrada en CSymbol provocará durante la compilación una advertencia sobre la duplicación de la variable. Por cierto, en los archivos adjuntos al artículo ya se han eliminado todas estas variables: podemos descargar los archivos y familiarizarnos con su contenido.
En el método que retorna la descripción de una propiedad de tipo entero, añadimos la descripción de la nueva propiedad del símbolo "índice en la ventana de Observación de mercado":
//+------------------------------------------------------------------+ //| Return the description of the symbol integer property | //+------------------------------------------------------------------+ string CSymbol::GetPropertyDescription(ENUM_SYMBOL_PROP_INTEGER property) { return ( property==SYMBOL_PROP_STATUS ? TextByLanguage("Статус","Status")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(string)this.GetProperty(property) ) : property==SYMBOL_PROP_INDEX_MW ? TextByLanguage("Индекс в окне \"Обзор рынка\"","Index in the \"Market Watch window\"")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetStatusDescription() ) : property==SYMBOL_PROP_CUSTOM ? TextByLanguage("Пользовательский символ","Custom symbol")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No")) ) : property==SYMBOL_PROP_CHART_MODE ? TextByLanguage("Тип цены для построения баров","Price type used for generating symbols bars")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetChartModeDescription() ) : property==SYMBOL_PROP_EXIST ? TextByLanguage("Символ с таким именем существует","Symbol with this name exists")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No")) ) : property==SYMBOL_PROP_SELECT ? TextByLanguage("Символ выбран в Market Watch","Symbol selected in Market Watch")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No")) ) : property==SYMBOL_PROP_VISIBLE ? TextByLanguage("Символ отображается в Market Watch","Symbol visible in Market Watch")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No")) ) : property==SYMBOL_PROP_SESSION_DEALS ? TextByLanguage("Количество сделок в текущей сессии","Number of deals in the current session")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_SESSION_BUY_ORDERS ? TextByLanguage("Общее число ордеров на покупку в текущий момент","Number of Buy orders at the moment")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_SESSION_SELL_ORDERS ? TextByLanguage("Общее число ордеров на продажу в текущий момент","Number of Sell orders at the moment")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_VOLUME ? TextByLanguage("Объем в последней сделке","Volume of the last deal")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_VOLUMEHIGH ? TextByLanguage("Максимальный объём за день","Maximal day volume")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_VOLUMELOW ? TextByLanguage("Минимальный объём за день","Minimal day volume")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_TIME ? TextByLanguage("Время последней котировки","Time of the last quote")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(this.GetProperty(property)==0 ? TextByLanguage("(Ещё не было тиков)","(No ticks yet)") : TimeMSCtoString(this.GetProperty(property))) ) : property==SYMBOL_PROP_DIGITS ? TextByLanguage("Количество знаков после запятой","Digits after decimal point")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(string)this.GetProperty(property) ) : property==SYMBOL_PROP_DIGITS_LOTS ? TextByLanguage("Количество знаков после запятой в значении лота","Digits after decimal point in the value of the lot")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(string)this.GetProperty(property) ) : property==SYMBOL_PROP_SPREAD ? TextByLanguage("Размер спреда в пунктах","Spread value in points")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(string)this.GetProperty(property) ) : property==SYMBOL_PROP_SPREAD_FLOAT ? TextByLanguage("Плавающий спред","Spread is floating")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No")) ) : property==SYMBOL_PROP_TICKS_BOOKDEPTH ? TextByLanguage("Максимальное количество показываемых заявок в стакане","Maximal number of requests shown in Depth of Market")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+ #ifdef __MQL5__(string)this.GetProperty(property) #else TextByLanguage("Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : property==SYMBOL_PROP_TRADE_CALC_MODE ? TextByLanguage("Способ вычисления стоимости контракта","Contract price calculation mode")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetCalcModeDescription() ) : property==SYMBOL_PROP_TRADE_MODE ? TextByLanguage("Тип исполнения ордеров","Order execution type")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetTradeModeDescription() ) : property==SYMBOL_PROP_START_TIME ? TextByLanguage("Дата начала торгов по инструменту","Date of symbol trade beginning")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : (this.GetProperty(property)==0 ? TextByLanguage(": (Отсутствует)",": (Not set)") : ": "+TimeMSCtoString(this.GetProperty(property)*1000)) ) : property==SYMBOL_PROP_EXPIRATION_TIME ? TextByLanguage("Дата окончания торгов по инструменту","Date of symbol trade end")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : (this.GetProperty(property)==0 ? TextByLanguage(": (Отсутствует)",": (Not set)") : ": "+TimeMSCtoString(this.GetProperty(property)*1000)) ) : property==SYMBOL_PROP_TRADE_STOPS_LEVEL ? TextByLanguage("Минимальный отступ от цены закрытия для установки Stop ордеров","Minimal indention from close price to place Stop orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(string)this.GetProperty(property) ) : property==SYMBOL_PROP_TRADE_FREEZE_LEVEL ? TextByLanguage("Дистанция заморозки торговых операций","Distance to freeze trade operations in points")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(string)this.GetProperty(property) ) : property==SYMBOL_PROP_TRADE_EXEMODE ? TextByLanguage("Режим заключения сделок","Deal execution mode")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetTradeExecDescription() ) : property==SYMBOL_PROP_SWAP_MODE ? TextByLanguage("Модель расчета свопа","Swap calculation model")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetSwapModeDescription() ) : property==SYMBOL_PROP_SWAP_ROLLOVER3DAYS ? TextByLanguage("День недели для начисления тройного свопа","Day of week to charge 3 days swap rollover")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+DayOfWeekDescription(this.SwapRollover3Days()) ) : property==SYMBOL_PROP_MARGIN_HEDGED_USE_LEG ? TextByLanguage("Расчет хеджированной маржи по наибольшей стороне","Calculating hedging margin using the larger leg")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+(this.GetProperty(property) ? TextByLanguage("Да","Yes") : TextByLanguage("Нет","No")) ) : property==SYMBOL_PROP_EXPIRATION_MODE ? TextByLanguage("Флаги разрешенных режимов истечения ордера","Flags of allowed order expiration modes")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetExpirationModeFlagsDescription() ) : property==SYMBOL_PROP_FILLING_MODE ? TextByLanguage("Флаги разрешенных режимов заливки ордера","Flags of allowed order filling modes")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetFillingModeFlagsDescription() ) : property==SYMBOL_PROP_ORDER_MODE ? TextByLanguage("Флаги разрешённых типов ордеров","Flags of allowed order types")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetOrderModeFlagsDescription() ) : property==SYMBOL_PROP_ORDER_GTC_MODE ? TextByLanguage("Срок действия StopLoss и TakeProfit ордеров","Expiration of Stop Loss and Take Profit orders")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetOrderGTCModeDescription() ) : property==SYMBOL_PROP_OPTION_MODE ? TextByLanguage("Тип опциона","Option type")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetOptionTypeDescription() ) : property==SYMBOL_PROP_OPTION_RIGHT ? TextByLanguage("Право опциона","Option right")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : ": "+this.GetOptionRightDescription() ) : property==SYMBOL_PROP_BACKGROUND_COLOR ? TextByLanguage("Цвет фона символа в Market Watch","Background color of symbol in Market Watch")+ (!this.SupportProperty(property) ? TextByLanguage(": Свойство не поддерживается",": Property not supported") : #ifdef __MQL5__ (this.GetProperty(property)==CLR_DEFAULT || this.GetProperty(property)==CLR_NONE ? TextByLanguage(": (Отсутствует)",": (Not set)") : ": "+::ColorToString((color)this.GetProperty(property),true)) #else TextByLanguage(": Свойство не поддерживается в MQL4","Property not supported in MQL4") #endif ) : "" ); } //+------------------------------------------------------------------+
Eliminamos del listado de implementación de los métodos de la clase CSymbol el segundo formulario del método Exist() y el método que retorna el número de dígitos tras la coma en el valor de la cifra:
//+------------------------------------------------------------------+
bool CSymbol::Exist(const string name) const
{
int total=::SymbolsTotal(false);
for(int i=0;i<total;i++)
if(::SymbolName(i,false)==name)
return true;
return false;
}
//+------------------------------------------------------------------+
//| Return the number of decimal places in the 'double' value |
//+------------------------------------------------------------------+
int CSymbol::GetDigits(const double value) const
{
string val_str=(string)value;
int len=::StringLen(val_str);
int n=len-::StringFind(val_str,".",0)-1;
if(::StringSubstr(val_str,len-1,1)=="0")
n--;
return n;
}
//+------------------------------------------------------------------+
Estos métodos sobran aquí. En esta clase no es necesario Exist() con el parámetro de entrada, por lo que ha sido trasladado al archivo de funciones de servicio DELib.mqh, donde debería estar, mientras que GetDigits() ahora se ubica en la clase básica CBaseObj.
El método Refresh() de la clase CSymbol se inicia en el temporizador y actualiza todos los datos del símbolo. En este mismo método realizaremos la búsqueda de los cambios en las propiedades del símbolo. Sin embargo, tenemos otro método más, RefreshRates(), que también se inicia desde el temporizador, pero con una alta frecuencia de actualización; en este método se actualizan solo los datos de cotización del símbolo. Si implementamos la búsqueda de los cambios en las propiedades de los símbolos en ambos métodos, esto provocará una ralentazación en los mensajes sobre los eventos.
La solución para esta situación podría ser la siguiente: el método RefreshRates() actualizará los datos de cotización y retornará la bandera sobre su correcta obtención. Este método se llamará de la misma forma que antes: desde su temporizador, pero también desde el método Refresh(), como complemento. De esta forma, se llamarán ambos métodos, como se hacía antes: cada uno en su propio temporizador, mientras que la búsqueda de cambios en las propiedades de los símbolos se dará solo en el método Refresh().
Vamos a introducir los cambios necesarios en los métodos RefreshRates() y Refresh():
//+------------------------------------------------------------------+ //| Update quote data by a symbol | //+------------------------------------------------------------------+ bool CSymbol::RefreshRates(void) { //--- Get quote data ::ResetLastError(); if(!::SymbolInfoTick(this.m_name,this.m_tick)) { this.m_global_error=::GetLastError(); return false; } //--- Update integer properties this.m_long_prop[SYMBOL_PROP_VOLUME] = (long)this.m_tick.volume; this.m_long_prop[SYMBOL_PROP_TIME] = this.TickTime(); //--- Update real properties this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASK)] = this.m_tick.ask; this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKHIGH)] = ::SymbolInfoDouble(this.m_name,SYMBOL_ASKHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_ASKLOW)] = ::SymbolInfoDouble(this.m_name,SYMBOL_ASKLOW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_BID)] = this.m_tick.bid; this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDHIGH)] = this.SymbolBidHigh(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_BIDLOW)] = this.SymbolBidLow(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LAST)] = this.m_tick.last; this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTHIGH)] = ::SymbolInfoDouble(this.m_name,SYMBOL_LASTHIGH); this.m_double_prop[this.IndexProp(SYMBOL_PROP_LASTLOW)] = ::SymbolInfoDouble(this.m_name,SYMBOL_LASTLOW); return true; } //+------------------------------------------------------------------+
Aquí, primero obtenemos los datos de cotización del símbolo, y si no hemos logrado obtener los datos, registramos el código de error y salimos del método retornando false. Si hemos conseguido obtener los datos, rellenamos las propiedades necesarias del símbolo y retornamos true.
//+------------------------------------------------------------------+ //| Update all symbol data | //+------------------------------------------------------------------+ void CSymbol::Refresh(void) { //--- Update quote data if(!this.RefreshRates()) return; #ifdef __MQL5__ ::ResetLastError(); if(!this.MarginRates()) { this.m_global_error=::GetLastError(); return; } #endif //--- Prepare event data this.m_is_event=false; ::ZeroMemory(this.m_struct_curr_symbol); this.m_hash_sum=0; //--- Update integer properties this.m_long_prop[SYMBOL_PROP_SELECT] = ::SymbolInfoInteger(this.m_name,SYMBOL_SELECT); this.m_long_prop[SYMBOL_PROP_VISIBLE] = ::SymbolInfoInteger(this.m_name,SYMBOL_VISIBLE); this.m_long_prop[SYMBOL_PROP_SESSION_DEALS] = ::SymbolInfoInteger(this.m_name,SYMBOL_SESSION_DEALS); this.m_long_prop[SYMBOL_PROP_SESSION_BUY_ORDERS] = ::SymbolInfoInteger(this.m_name,SYMBOL_SESSION_BUY_ORDERS); this.m_long_prop[SYMBOL_PROP_SESSION_SELL_ORDERS] = ::SymbolInfoInteger(this.m_name,SYMBOL_SESSION_SELL_ORDERS); this.m_long_prop[SYMBOL_PROP_VOLUMEHIGH] = ::SymbolInfoInteger(this.m_name,SYMBOL_VOLUMEHIGH); this.m_long_prop[SYMBOL_PROP_VOLUMELOW] = ::SymbolInfoInteger(this.m_name,SYMBOL_VOLUMELOW); this.m_long_prop[SYMBOL_PROP_SPREAD] = ::SymbolInfoInteger(this.m_name,SYMBOL_SPREAD); this.m_long_prop[SYMBOL_PROP_TICKS_BOOKDEPTH] = ::SymbolInfoInteger(this.m_name,SYMBOL_TICKS_BOOKDEPTH); this.m_long_prop[SYMBOL_PROP_START_TIME] = ::SymbolInfoInteger(this.m_name,SYMBOL_START_TIME); this.m_long_prop[SYMBOL_PROP_EXPIRATION_TIME] = ::SymbolInfoInteger(this.m_name,SYMBOL_EXPIRATION_TIME); this.m_long_prop[SYMBOL_PROP_TRADE_STOPS_LEVEL] = ::SymbolInfoInteger(this.m_name,SYMBOL_TRADE_STOPS_LEVEL); this.m_long_prop[SYMBOL_PROP_TRADE_FREEZE_LEVEL] = ::SymbolInfoInteger(this.m_name,SYMBOL_TRADE_FREEZE_LEVEL); this.m_long_prop[SYMBOL_PROP_BACKGROUND_COLOR] = this.SymbolBackgroundColor(); //--- Update real properties this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_VALUE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_VALUE_PROFIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_VALUE_LOSS); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_TICK_SIZE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_TICK_SIZE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_CONTRACT_SIZE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_TRADE_CONTRACT_SIZE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MIN)] = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_MIN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_MAX)] = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_MAX); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_STEP)] = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_STEP); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_LIMIT)] = ::SymbolInfoDouble(this.m_name,SYMBOL_VOLUME_LIMIT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_LONG)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_LONG); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SWAP_SHORT)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SWAP_SHORT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_INITIAL)] = ::SymbolInfoDouble(this.m_name,SYMBOL_MARGIN_INITIAL); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_MAINTENANCE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_MARGIN_MAINTENANCE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_VOLUME)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_TURNOVER)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_TURNOVER); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_INTEREST)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_INTEREST); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_BUY_ORDERS_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_SELL_ORDERS_VOLUME); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_OPEN)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_OPEN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_CLOSE)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_CLOSE); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_AW)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_AW); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_PRICE_SETTLEMENT); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_PRICE_LIMIT_MIN); this.m_double_prop[this.IndexProp(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX)] = ::SymbolInfoDouble(this.m_name,SYMBOL_SESSION_PRICE_LIMIT_MAX); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUME_REAL)] = this.SymbolVolumeReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMEHIGH_REAL)] = this.SymbolVolumeHighReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_VOLUMELOW_REAL)] = this.SymbolVolumeLowReal(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_OPTION_STRIKE)] = this.SymbolOptionStrike(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_ACCRUED_INTEREST)] = this.SymbolTradeAccruedInterest(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_FACE_VALUE)] = this.SymbolTradeFaceValue(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_TRADE_LIQUIDITY_RATE)] = this.SymbolTradeLiquidityRate(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_HEDGED)] = this.SymbolMarginHedged(); this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_INITIAL)] = this.m_margin_rate.Long.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL)] = this.m_margin_rate.BuyStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL)] = this.m_margin_rate.BuyLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL)] = this.m_margin_rate.BuyStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE)] = this.m_margin_rate.Long.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE)] = this.m_margin_rate.BuyStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE)] = this.m_margin_rate.BuyLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE)] = this.m_margin_rate.BuyStopLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_INITIAL)] = this.m_margin_rate.Short.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL)] = this.m_margin_rate.SellStop.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL)] = this.m_margin_rate.SellLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL)] = this.m_margin_rate.SellStopLimit.Initial; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE)] = this.m_margin_rate.Short.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE)] = this.m_margin_rate.SellStop.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE)] = this.m_margin_rate.SellLimit.Maintenance; this.m_double_prop[this.IndexProp(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE)]= this.m_margin_rate.SellStopLimit.Maintenance; //--- Fill in the current symbol data structure this.m_struct_curr_symbol.ask = this.Ask(); this.m_struct_curr_symbol.ask_high = this.AskHigh(); this.m_struct_curr_symbol.ask_low = this.AskLow(); this.m_struct_curr_symbol.bid_last = (this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.Bid() : this.Last()); this.m_struct_curr_symbol.bid_last_high = (this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.BidHigh() : this.LastHigh()); this.m_struct_curr_symbol.bid_last_low = (this.ChartMode()==SYMBOL_CHART_MODE_BID ? this.BidLow() : this.LastLow()); this.m_struct_curr_symbol.volume = this.Volume(); this.m_struct_curr_symbol.session_deals = this.SessionDeals(); this.m_struct_curr_symbol.session_buy_orders = this.SessionBuyOrders(); this.m_struct_curr_symbol.session_sell_orders = this.SessionSellOrders(); this.m_struct_curr_symbol.volume_high_day = this.VolumeHigh(); this.m_struct_curr_symbol.volume_low_day = this.VolumeLow(); this.m_struct_curr_symbol.spread = this.Spread(); this.m_struct_curr_symbol.stops_level = this.TradeStopLevel(); this.m_struct_curr_symbol.freeze_level = this.TradeFreezeLevel(); this.m_struct_curr_symbol.volume_limit = this.VolumeLimit(); this.m_struct_curr_symbol.swap_long = this.SwapLong(); this.m_struct_curr_symbol.swap_short = this.SwapShort(); this.m_struct_curr_symbol.session_volume = this.SessionVolume(); this.m_struct_curr_symbol.session_turnover = this.SessionTurnover(); this.m_struct_curr_symbol.session_interest = this.SessionInterest(); this.m_struct_curr_symbol.session_buy_ord_volume = this.SessionBuyOrdersVolume(); this.m_struct_curr_symbol.session_sell_ord_volume = this.SessionSellOrdersVolume(); this.m_struct_curr_symbol.session_open = this.SessionOpen(); this.m_struct_curr_symbol.session_close = this.SessionClose(); this.m_struct_curr_symbol.session_aw = this.SessionAW(); this.m_struct_curr_symbol.volume_real_day = this.VolumeReal(); this.m_struct_curr_symbol.volume_high_real_day = this.VolumeHighReal(); this.m_struct_curr_symbol.volume_low_real_day = this.VolumeLowReal(); this.m_struct_curr_symbol.option_strike = this.OptionStrike(); this.m_struct_curr_symbol.trade_mode = this.TradeMode(); //--- Hash sum calculation this.m_hash_sum+=(double)this.m_struct_curr_symbol.volume; this.m_hash_sum+=(double)this.m_struct_curr_symbol.session_deals; this.m_hash_sum+=(double)this.m_struct_curr_symbol.session_buy_orders; this.m_hash_sum+=(double)this.m_struct_curr_symbol.session_sell_orders; this.m_hash_sum+=(double)this.m_struct_curr_symbol.volume_high_day; this.m_hash_sum+=(double)this.m_struct_curr_symbol.volume_low_day; this.m_hash_sum+=(double)this.m_struct_curr_symbol.spread; this.m_hash_sum+=(double)this.m_struct_curr_symbol.stops_level; this.m_hash_sum+=(double)this.m_struct_curr_symbol.freeze_level; this.m_hash_sum+=this.m_struct_curr_symbol.ask; this.m_hash_sum+=this.m_struct_curr_symbol.ask_high; this.m_hash_sum+=this.m_struct_curr_symbol.ask_low; this.m_hash_sum+=this.m_struct_curr_symbol.bid_last; this.m_hash_sum+=this.m_struct_curr_symbol.bid_last_high; this.m_hash_sum+=this.m_struct_curr_symbol.bid_last_low; this.m_hash_sum+=this.m_struct_curr_symbol.volume_limit; this.m_hash_sum+=this.m_struct_curr_symbol.swap_long; this.m_hash_sum+=this.m_struct_curr_symbol.swap_short; this.m_hash_sum+=this.m_struct_curr_symbol.session_volume; this.m_hash_sum+=this.m_struct_curr_symbol.session_turnover; this.m_hash_sum+=this.m_struct_curr_symbol.session_interest; this.m_hash_sum+=this.m_struct_curr_symbol.session_buy_ord_volume; this.m_hash_sum+=this.m_struct_curr_symbol.session_sell_ord_volume; this.m_hash_sum+=this.m_struct_curr_symbol.session_open; this.m_hash_sum+=this.m_struct_curr_symbol.session_close; this.m_hash_sum+=this.m_struct_curr_symbol.session_aw; this.m_hash_sum+=this.m_struct_curr_symbol.volume_real_day; this.m_hash_sum+=this.m_struct_curr_symbol.volume_high_real_day; this.m_hash_sum+=this.m_struct_curr_symbol.volume_low_real_day; this.m_hash_sum+=this.m_struct_curr_symbol.option_strike; this.m_hash_sum+=this.m_struct_curr_symbol.trade_mode; //--- First launch if(this.m_struct_prev_symbol.trade_mode==WRONG_VALUE) { this.m_struct_prev_symbol=this.m_struct_curr_symbol; this.m_hash_sum_prev=this.m_hash_sum; return; } //--- If symbol's hash sum changed if(this.m_hash_sum!=this.m_hash_sum_prev) { this.m_event_code=this.SetEventCode(); this.SetTypeEvent(); CEventBaseObj *event=this.GetEvent(WRONG_VALUE,false); if(event!=NULL) { ENUM_SYMBOL_EVENT event_id=(ENUM_SYMBOL_EVENT)event.ID(); if(event_id!=SYMBOL_EVENT_NO_EVENT) { this.m_is_event=true; } } this.m_hash_sum_prev=this.m_hash_sum; } } //+------------------------------------------------------------------+
Aquí: en primer lugar, llamamos al método RefreshRates(), y si no hemos logrado obtener los datos de cotización, ya no tendrá sentido obtener el resto de datos, por lo que salimos del método.
A continuación, reseteamos la bandera de evento, la estructura del estado actual de las propiedades del símbolo y la suma hash actual. Después, rellenamos todas las propiedades del símbolo con los datos actuales y registramos estos datos en la estructura del estado actual de las propiedades del símbolo. Tras rellenar la estructura, calculamos la suma hash actual.
Si se trata del primer inicio (la propiedadad del símbolo SYMBOL_TRADE_MODE se ha establecido con el valor WRONG_VALUE), guardamos los valores de la estructura en la estructura del estado pasado , registramos la suma hash actual en la suma hash anterior y salimos del método.
Si no se trata del primer inicio, deberemos comprobar si el valor de la suma hash actual y la pasada son distintos.
Si la suma hash ha cambiado, significará que ha habido algún cambio en las propiedades del símbolo, así que llamamos al método de establecimiento del código de evento, al método de obtención de un evento del código de eventos y de registro de un evento en la lista de eventos sucedidos, obtenemos el último evento de los eventos recién añadidos de la lista, comprobamos el tipo de evento, y si no se trata de "No hay evento", activamos la bandera de evento. Finalmente, guardamos la suma hash actual como pasada para las comprobaciones posteriores.
Con esto, podemos considerar por finalizada la mejora de la clase CSymbol para la búsqueda de eventos y el trabajo con el nuevo objeto básico.
La clase de objeto de símbolo está preparada. Ahora, cada símbolo podrá monitorear sus eventos y ubicarlos en su propia lista de eventos. Nosotros usamos una colección de símbolos, y por consiguiente, debemos iterar en un ciclo por todos los símbolos de la colección y obetener de cada uno de ellos una lista con sus eventos. Y todos estos eventos deberemos ubicarlos en la lista de eventos de la colección (ahora la colección también tiene una lista así, dado que está ubicada en el objeto básico CBaseObj). Solo queda interrogar a la lista de eventos y determinar si ha sucedido un evento o varios de ellos al mismo tiempo para cada uno de los símbolos de la colección.
Bien. Abrimos el archivo de clase de la colección de símbolos SymbolsCollection.mqh e introducimos los cambios necesarios:
//+------------------------------------------------------------------+ //| SymbolsCollection.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include <Arrays\ArrayString.mqh> #include "ListObj.mqh" #include "..\Services\Select.mqh" #include "..\Objects\Symbols\Symbol.mqh" #include "..\Objects\Symbols\SymbolFX.mqh" #include "..\Objects\Symbols\SymbolFXMajor.mqh" #include "..\Objects\Symbols\SymbolFXMinor.mqh" #include "..\Objects\Symbols\SymbolFXExotic.mqh" #include "..\Objects\Symbols\SymbolFXRub.mqh" #include "..\Objects\Symbols\SymbolMetall.mqh" #include "..\Objects\Symbols\SymbolIndex.mqh" #include "..\Objects\Symbols\SymbolIndicative.mqh" #include "..\Objects\Symbols\SymbolCrypto.mqh" #include "..\Objects\Symbols\SymbolCommodity.mqh" #include "..\Objects\Symbols\SymbolExchange.mqh" #include "..\Objects\Symbols\SymbolFutures.mqh" #include "..\Objects\Symbols\SymbolCFD.mqh" #include "..\Objects\Symbols\SymbolStocks.mqh" #include "..\Objects\Symbols\SymbolBonds.mqh" #include "..\Objects\Symbols\SymbolOption.mqh" #include "..\Objects\Symbols\SymbolCollateral.mqh" #include "..\Objects\Symbols\SymbolCustom.mqh" #include "..\Objects\Symbols\SymbolCommon.mqh" //+------------------------------------------------------------------+ //| Symbol collection | //+------------------------------------------------------------------+ class CSymbolsCollection : public CBaseObj { private: CListObj m_list_all_symbols; // The list of all symbol objects CArrayString m_list_names; // Symbol name control list ENUM_SYMBOLS_MODE m_mode_list; // Mode of working with symbol lists ENUM_SYMBOL_EVENT m_last_event; // The last event string m_array_symbols[]; // The array of used symbols passed from the program int m_delta_symbol; // Difference in the number of symbols compared to the previous check int m_total_symbols; // Number of symbols in the Market Watch window int m_total_symbol_prev; // Number of symbols in the Market Watch window during the previous check //--- Return the flag of a symbol object presence by its name in the (1) list of all symbols, (2) Market Watch window, (3) control list bool IsPresentSymbolInList(const string symbol_name); bool IsPresentSymbolInMW(const string symbol_name); bool IsPresentSymbolInControlList(const string symbol_name); //--- Create the symbol object and place it to the list bool CreateNewSymbol(const ENUM_SYMBOL_STATUS symbol_status,const string name,const int index); //--- Return the (1) type of a used symbol list (Market watch/Server), //--- (2) the number of visible symbols, (3) symbol index in the Market Watch window ENUM_SYMBOLS_MODE TypeSymbolsList(const string &symbol_used_array[]); int SymbolsTotalVisible(void) const; int SymbolIndexInMW(const string name) const; //--- Define a symbol affiliation with a group by name and return it ENUM_SYMBOL_STATUS SymbolStatus(const string symbol_name) const; //--- Return a symbol affiliation with a category by custom criteria ENUM_SYMBOL_STATUS StatusByCustomPredefined(const string symbol_name) const; //--- Return a symbol affiliation with categories by margin calculation ENUM_SYMBOL_STATUS StatusByCalcMode(const string symbol_name) const; //--- Return a symbol affiliation with pre-defined (1) majors, (2) minors, (3) exotics, (4) RUB, //--- (5) indicatives, (6) metals, (7) commodities, (8) indices, (9) cryptocurrency, (10) options bool IsPredefinedFXMajor(const string name) const; bool IsPredefinedFXMinor(const string name) const; bool IsPredefinedFXExotic(const string name) const; bool IsPredefinedFXRUB(const string name) const; bool IsPredefinedIndicative(const string name) const; bool IsPredefinedMetall(const string name) const; bool IsPredefinedCommodity(const string name) const; bool IsPredefinedIndex(const string name) const; bool IsPredefinedCrypto(const string name) const; bool IsPredefinedOption(const string name) const; public: //--- Return the full collection list 'as is' CArrayObj *GetList(void) { return &this.m_list_all_symbols; } //--- Return the list by selected (1) integer, (2) real and (3) string properties meeting the compared criterion CArrayObj *GetList(ENUM_SYMBOL_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_SYMBOL_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_SYMBOL_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::BySymbolProperty(this.GetList(),property,value,mode); } //--- Return the (1) symbol object, (2) the symbol object index from the list by a name CSymbol *GetSymbolByName(const string name); int GetSymbolIndexByName(const string name); //--- Return the number of new symbols in the Market Watch window int NewSymbols(void) const { return this.m_delta_symbol; } //--- Return (1) the mode of working with symbol lists, (2) the event flag and (3) the event of one of the collection symbols ENUM_SYMBOLS_MODE ModeSymbolsList(void) const { return this.m_mode_list; } bool IsEvent(void) const { return this.m_is_event; } int GetLastEventsCode(void) const { return this.m_event_code; } ENUM_SYMBOL_EVENT GetLastEvent(void) const { return this.m_last_event; } //--- Return the number of symbols in the collection int GetSymbolsCollectionTotal(void) const { return this.m_list_all_symbols.Total(); } //--- Constructor CSymbolsCollection(); //--- (1) Set the list of used symbols, (2) creating the symbol list (Market Watch or the complete list) bool SetUsedSymbols(const string &symbol_used_array[]); bool CreateSymbolsList(const bool flag); //--- Save names of used Market Watch symbols void CopySymbolsNames(void); //--- Update (1) all, (2) quote data of the collection symbols virtual void Refresh(void); void RefreshRates(void); //--- Working with the events of the (1) collection symbol list, (2) market watch window void SymbolsEventsControl(void); void MarketWatchEventsControl(const bool send_events=true); //--- Return the description of the (1) Market Watch window event, (2) mode of working with symbols string EventDescription(const ENUM_SYMBOL_EVENT event); string ModeSymbolsListDescription(void); }; //+------------------------------------------------------------------+
Vamos a usar el archivo CArrayString, incluido desde la biblioteca estándar, para crear la plantilla de la ventana de "Observación de mercado". En esta lista, vamos a guardar una copia del conjunto de símbolos de la observación de mercado y comparar el estado actual de la lista de símbolos en la ventana con el estado actual de la lista de símbolos en la plantilla. Ante los otros cambios, reaccionaremos creando los eventos de la ventana de "Observación de mercado".
En la variable m_last_event, registraremos el último evento sucedido con cualquiera de los símbolos en la colección. De esta forma, en la variable se guardará el último evento sucedido en uno de los símbolos usados.
La matriz m_array_symbols transmite la matriz de símbolos utilizados en el programa desde el programa de control a la clase de colección de símbolos.
En las variables de miembro de clase m_total_symbols y m_total_symbols_prev, guardaremos el número actual y pasado de símbolos en la ventana de "Observación de mercado". La comparación de estas variables nos permitirá conocer los eventos de adición o eliminación de símbolos en la observación de mercado.
Los métodos privados de clase IsPresentSymbolInMW() y IsPresentSymbolInControlList() retornan las banderas de presencia de un símbolos según su nombre en la ventana de "Observación de mercado" y la lista de plantilla de la ventana de observación de mercado, respectivamente. Los métodos SymbolsTotalVisible() y SymbolIndexInMW(), a su vez, retornan el número de símbolos visibles en la ventana de "Observación de mercado" y el índice del símbolo en la lista de esta ventana, respectivamente.
En la sección pública de la clase, añadimos los métodos:
IsEvent() — retorna la bandera de presencia de cualquier evento en la colección de símbolos o en la ventana de "Observación de mercado",
GetLastEventsCode() — retorna el código del último evento en la colección de símbolos o en la ventana de "Observación de mercado",
GetLastEvent() — retorna el último evento en la colección de símbolos o en la ventana de "Observación de mercado",
GetSymbolsCollectionTotal() — retorna el número total de símbolos en la colección,
CreateSymbolsList() — crea la lista de colección al trabajar con la ventana de "Observación de mercado" o con la lista completa de símbolos en el servidor (no más de 1000),
CopySymbolsNames() — crea la plantilla de símbolos de la ventana de "Observación de mercado" a partir de la lista con todos los símbolos de la colección,
Refresh() — ahora el método se declara como virtual, dado que se declara virtual en la clase del objeto básico (y la colección de objetos ahora se crea usando como base la clase de objeto básico CBaseObj),
SymbolsEventsControl() — método de trabajo con la lista de colección de símbolos para determinar los eventos de colección de símbolos,
MarketWatchEventsControl() — método de trabajo con la ventana de "Observación de mercado" para determinar los eventos en la ventana de observación de mercado,
EventDescription() — retorna la descripción de un evento de la colección de símbolos,
ModeSymbolsListDescription() — retorna la descripción del modo de trabajo con los símbolos.
Vamos a echar un vistazo a la implementación de los métodos.
Inicializamos en la lista de inicialización del constructor de clase las variables para trabajar con la ventana de "Observación de mercado", y también sustituimos en el cuerpo de la clase la clasificación de la lista de símbolos de la colección con clasificación según el nombre por la clasificación según el índice en la ventana de "Observación de mercado", además de limpiar la lista de la plantilla de la ventana de observación de mercado.
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CSymbolsCollection::CSymbolsCollection(void) : m_total_symbol_prev(0), m_delta_symbol(0), m_mode_list(SYMBOLS_MODE_CURRENT) { this.m_list_all_symbols.Sort(SORT_BY_SYMBOL_INDEX_MW); this.m_list_all_symbols.Clear(); this.m_list_all_symbols.Type(COLLECTION_SYMBOLS_ID); this.m_list_names.Clear(); } //+------------------------------------------------------------------+
Dado que en la ventana de "Observación de mercado", el símbolo puede encontrarse, pero no representarse (propiedad del símbolo SYMBOL_VISIBLE, algunos símbolos (normalmente, se trata de cursos cruzados, imprescindibles para calcular los requisitos de margen y el beneficio en la divisa del depósito) se seleccionan automáticamente, aunque en este caso pueden no representarse en Market Watch), para saber el número de símbolos solo visibles, deberemos calcular en el ciclo por los símbolos de la ventana solo aquellos símbolos que tienen establecida esta propiedad.
El método SymbolsTotalVisible() retorna el número de símbolos visibles en la ventana de "Observación de mercado":
//+------------------------------------------------------------------+ //| Return the number of visible symbols in the Market Watch window | //+------------------------------------------------------------------+ int CSymbolsCollection::SymbolsTotalVisible(void) const { int total=::SymbolsTotal(true),n=0; for(int i=0;i<total;i++) { if(!::SymbolInfoInteger(::SymbolName(i,true),SYMBOL_VISIBLE)) continue; n++; } return n; } //+------------------------------------------------------------------+
Método que retorna el índice del símbolo en la lista de la ventana de "Observación de mercado":
//+------------------------------------------------------------------+ //| Return symbol index in the Market Watch window | //+------------------------------------------------------------------+ int CSymbolsCollection::SymbolIndexInMW(const string name) const { int total=::SymbolsTotal(true); for(int i=0;i<total;i++) { if(!::SymbolInfoInteger(::SymbolName(i,true),SYMBOL_VISIBLE)) continue; if(SymbolName(i,true)==name) return i; } return WRONG_VALUE; } //+------------------------------------------------------------------+
Al trabajar con la lista de símbolos de la ventana de "Observación de mercado", tenemos que conocer el índice de cada uno de los símbolos en la lista de la ventana, para poder sincronizar la ubicación de los símbolos en la lista de símbolos de la colección con la ubicación de los símbolos en la ventana de observación de mercado. Por ejemplo, esto podría ser necesario para crear una ventana propia para la lista de símbolos, totalmente sincronizada con la ventana del terminal. El índice será una de las propiedades del símbolo, lo que permitirá clasificar la lista según esta propiedad. Además, el índice se transmitirá al constructor de clase del símbolo asbtracto.
Método que retorna la bandera de presencia de un símbolo visible en la ventana de "Observación de mercado":
//+------------------------------------------------------------------+ //| Return the visible symbol object presence flag | //| by its name in the Market Watch window | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPresentSymbolInMW(const string symbol_name) { int total=SymbolsTotal(true); for(int i=0;i<total;i++) { string name=::SymbolName(i,true); if(!::SymbolInfoInteger(name,SYMBOL_VISIBLE)) continue; if(name==symbol_name) return true; } return false; } //+------------------------------------------------------------------+
Transmitimos al método el nombre del símbolo, después iteramos con el símbolo invisible en un ciclo por la lista completa de símbolosseleccionados en la ventana de observación de mercado, comparamos el nombre del siguiente símbolo con el transmitido al método, y si los nombres coinciden, retornamos true. Si el nombre no ha sido encontrado en la lista, retornamos false.
Método que retorna la bandera de presencia de un símbolo en la lista de plantilla de la ventana de "Observación de mercado":
//+------------------------------------------------------------------+ //| Return the flag of a symbol object presence in the control list | //+------------------------------------------------------------------+ bool CSymbolsCollection::IsPresentSymbolInControlList(const string symbol_name) { int total=this.m_list_names.Total(); for(int i=0;i<total;i++) { string name=this.m_list_names.At(i); if(name==NULL) continue; if(name==symbol_name) return true; } return false; } //+------------------------------------------------------------------+
Transmitimos al método el nombre del símbolo buscado. Obtenemos el siguiente símbolo en el ciclo por la lista de plantilla de la ventana de observación de mercado, y si su nombre coincide con el transmitido al método, retornamos true, de lo contrario, false.
Método para crear una lista al trabajar con la ventana de "Observación de mercado" o con la lista completa de símbolos en el servidor:
//+------------------------------------------------------------------+ //| Creating the symbol list (Market Watch or the complete list) | //+------------------------------------------------------------------+ bool CSymbolsCollection::CreateSymbolsList(const bool flag) { bool res=true; int total=::SymbolsTotal(flag); for(int i=0;i<total && i<SYMBOLS_COMMON_TOTAL;i++) { string name=::SymbolName(i,flag); if(flag && !::SymbolInfoInteger(name,SYMBOL_VISIBLE)) continue; ENUM_SYMBOL_STATUS status=this.SymbolStatus(name); bool add=this.CreateNewSymbol(status,name,i); res &=add; if(!add) continue; } return res; } //+------------------------------------------------------------------+
Transmitimos al método la bandera que establece el modo de búsqueda: true — trabajar con los símbolos seleccionados en la ventana de "Observación de mercado", false — trabajar con la lista completa de símbolos disponibles en el servidor. Obtenemos el número total de símbolos dependiendo de la bandera, o bien en la ventana de observación de mercado, o bien en el servidor, y luego, en un ciclo por una lista con un tamaño no superior al de la magnitud establecida por la constante SYMBOLS_COMMON_TOTAL en el archivo Defines.mqh (1000 símbolos), obtenemos el nombre del siguiente símbolo de la lista, comprobamos su propiedad de visibilidad al trabajar con la ventana de observación de mercado, y si el símbolo es invisible, lo omitimos.
A continuación, obtenemos el estado del objeto de símbolo según su nombre y añadimos el símbolo a la lista de completa de símbolos de la colección con la ayuda del método CreateNewSymbol(), que ya analizamos en el artículo anterior. (Hay que destacar que el método ha cambiado un poco, debido a la adición de una nueva propiedad del símbolo: su índice en la lista de símbolos de la ventana de "Observación de mercado", ahora, al objeto de símbolo se la transmite también el índice).
Introducimos en la variable que retorna el resultado del funcionamiento del método los resultados de la adición de cada símbolo en la lista completa de símbolos de la colección, y retornamos desde el método el valor final de esta variable al finalizar el ciclo completo del procesamiento de símbolos.
Vamos a analizar el método mejorado para la creación de un objeto de símbolo y su ubicación en la lista:
//+------------------------------------------------------------------+ //| Create a symbol object and place it to the list | //+------------------------------------------------------------------+ bool CSymbolsCollection::CreateNewSymbol(const ENUM_SYMBOL_STATUS symbol_status,const string name,const int index) { if(this.IsPresentSymbolInList(name)) { return true; } if(#ifdef __MQL5__ !::SymbolInfoInteger(name,SYMBOL_EXIST) #else !Exist(name) #endif ) { string t1=TextByLanguage("Ошибка входных данных: нет символа ","Input error: no "); string t2=TextByLanguage(" на сервере"," symbol on the server"); ::Print(DFUN,t1,name,t2); this.m_global_error=ERR_MARKET_UNKNOWN_SYMBOL; return false; } CSymbol *symbol=NULL; switch(symbol_status) { case SYMBOL_STATUS_FX : symbol=new CSymbolFX(name,index); break; // Forex symbol case SYMBOL_STATUS_FX_MAJOR : symbol=new CSymbolFXMajor(name,index); break; // Major Forex symbol case SYMBOL_STATUS_FX_MINOR : symbol=new CSymbolFXMinor(name,index); break; // Minor Forex symbol case SYMBOL_STATUS_FX_EXOTIC : symbol=new CSymbolFXExotic(name,index); break; // Exotic Forex symbol case SYMBOL_STATUS_FX_RUB : symbol=new CSymbolFXRub(name,index); break; // Forex symbol/RUR case SYMBOL_STATUS_METAL : symbol=new CSymbolMetall(name,index); break; // Metal case SYMBOL_STATUS_INDEX : symbol=new CSymbolIndex(name,index); break; // Index case SYMBOL_STATUS_INDICATIVE : symbol=new CSymbolIndicative(name,index); break; // Indicative case SYMBOL_STATUS_CRYPTO : symbol=new CSymbolCrypto(name,index); break; // Cryptocurrency symbol case SYMBOL_STATUS_COMMODITY : symbol=new CSymbolCommodity(name,index); break; // Commodity case SYMBOL_STATUS_EXCHANGE : symbol=new CSymbolExchange(name,index); break; // Exchange symbol case SYMBOL_STATUS_FUTURES : symbol=new CSymbolFutures(name,index); break; // Futures case SYMBOL_STATUS_CFD : symbol=new CSymbolCFD(name,index); break; // CFD case SYMBOL_STATUS_STOCKS : symbol=new CSymbolStocks(name,index); break; // Stock case SYMBOL_STATUS_BONDS : symbol=new CSymbolBonds(name,index); break; // Bond case SYMBOL_STATUS_OPTION : symbol=new CSymbolOption(name,index); break; // Option case SYMBOL_STATUS_COLLATERAL : symbol=new CSymbolCollateral(name,index); break; // Non-tradable asset case SYMBOL_STATUS_CUSTOM : symbol=new CSymbolCustom(name,index); break; // Custom symbol default : symbol=new CSymbolCommon(name,index); break; // The rest } if(symbol==NULL) { ::Print(DFUN,TextByLanguage("Не удалось создать объект-символ ","Failed to create symbol object "),name); return false; } if(!this.m_list_all_symbols.Add(symbol)) { string t1=TextByLanguage("Не удалось добавить символ ","Failed to add "); string t2=TextByLanguage(" в список"," symbol to the list"); ::Print(DFUN,t1,name,t2); delete symbol; return false; } return true; } //+------------------------------------------------------------------+
Como podemos ver por el listado, aquí transmitimos el índice al método de forma adicional, enviando también este índice a cada uno de los constructores de las clases de los objetos de símbolo, junto con el nombre del símbolo. Por consiguiente, será necesario mejorar cada una de las clases herederas de la clase de símbolo abstracto CSymbol.
Vamos a estudiar esta mejora usando como ejemplo la clase CSymbolFX:
//+------------------------------------------------------------------+ //| SymbolFX.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Symbol.mqh" //+------------------------------------------------------------------+ //| Forex symbol | //+------------------------------------------------------------------+ class CSymbolFX : public CSymbol { public: //--- Constructor CSymbolFX(const string name,const int index) : CSymbol(SYMBOL_STATUS_FX,name,index) {} //--- Supported integer properties of a symbol virtual bool SupportProperty(ENUM_SYMBOL_PROP_INTEGER property); //--- Supported real properties of a symbol virtual bool SupportProperty(ENUM_SYMBOL_PROP_DOUBLE property); //--- Supported string properties of a symbol virtual bool SupportProperty(ENUM_SYMBOL_PROP_STRING property); //--- Display a short symbol description in the journal virtual void PrintShort(void); }; //+------------------------------------------------------------------+
Aquí, además del nombre del símbolo, transmitimos al constructor de la clase su índice. Asimismo, transmitimos este índice al constructor de la clase padre CSymbol en la lista de inicialización.
Esto es todo lo que debemos cambiar en todas las clases herederas del símbolo abstracto. Ya hemos introducido en los archivos adjuntos al final del artículo todos los cambios en las clases de los objetos de símbolo.
Método mejorado para esteblecer la lista de símbolos usados en la colección:
//+------------------------------------------------------------------+ //| Set the list of used symbols | //+------------------------------------------------------------------+ bool CSymbolsCollection::SetUsedSymbols(const string &symbol_used_array[]) { ::ArrayCopy(this.m_array_symbols,symbol_used_array); this.m_mode_list=this.TypeSymbolsList(this.m_array_symbols); this.m_list_all_symbols.Clear(); this.m_list_all_symbols.Sort(SORT_BY_SYMBOL_INDEX_MW); //--- Use only the current symbol if(this.m_mode_list==SYMBOLS_MODE_CURRENT) { string name=::Symbol(); ENUM_SYMBOL_STATUS status=this.SymbolStatus(name); return this.CreateNewSymbol(status,name,this.SymbolIndexInMW(name)); } else { bool res=true; //--- Use the pre-defined symbol list if(this.m_mode_list==SYMBOLS_MODE_DEFINES) { int total=::ArraySize(this.m_array_symbols); for(int i=0;i<total;i++) { string name=this.m_array_symbols[i]; ENUM_SYMBOL_STATUS status=this.SymbolStatus(name); bool add=this.CreateNewSymbol(status,name,this.SymbolIndexInMW(name)); res &=add; if(!add) continue; } return res; } //--- Use the full list of the server symbols else if(this.m_mode_list==SYMBOLS_MODE_ALL) { return this.CreateSymbolsList(false); } //--- Use the symbol list from the Market Watch window else if(this.m_mode_list==SYMBOLS_MODE_MARKET_WATCH) { this.MarketWatchEventsControl(false); return true; } } return false; } //+------------------------------------------------------------------+
Aquí: copiamos directamente la matriz de símbolos usados transmitida desde el programa de control en nuestra propia matriz. Guardamos el modo de trabajo con los símbolos y establecemos la clasificación de la lista completa de símbolos en el modo de clasificación según el índice. Ahora, transmitimos al método de creación de un nuevo objeto de símbolo, además del nombre del símbolo, su índice.
Si usamos la lista completa de todos los símbolos en el servidor, llamaremos al método de construcción de la lista de símbolos de la colección con la bandera = false, lo que indica la construcción de la lista completa de símbolos en el servidor,
y al usar la lista de la ventana de "Observación de mercado", llamaremos al método de trabajo con la ventana de observación de mercado con la bandera = false, lo que no indicará que el método tenga prohibido trabajar con eventos, sino solo la necesidad de crear una lista y recordar sus datos.
Métodos de trabajo con los eventos de todos los símbolos de la colección:
//+------------------------------------------------------------------+ //| Working with the events of the collection symbol list | //+------------------------------------------------------------------+ void CSymbolsCollection::SymbolsEventsControl(void) { this.m_is_event=false; this.m_list_events.Clear(); this.m_list_events.Sort(); //--- The full update of all collection symbols int total=this.m_list_all_symbols.Total(); for(int i=0;i<total;i++) { CSymbol *symbol=this.m_list_all_symbols.At(i); if(symbol==NULL) continue; symbol.Refresh(); if(!symbol.IsEvent()) continue; this.m_is_event=true; CArrayObj *list=symbol.GetListEvents(); if(list==NULL) continue; this.m_event_code=symbol.GetEventCode(); int n=list.Total(); for(int j=0; j<n; j++) { CEventBaseObj *event=list.At(j); if(event==NULL) continue; ENUM_SYMBOL_EVENT event_id=(ENUM_SYMBOL_EVENT)event.ID(); if(event_id==SYMBOL_EVENT_NO_EVENT) continue; this.m_last_event=event_id; if(this.EventAdd((ushort)event.ID(),event.LParam(),event.DParam(),event.SParam())) { ::EventChartCustom(this.m_chart_id,(ushort)event_id,event.LParam(),event.DParam(),event.SParam()); } } } } //+------------------------------------------------------------------+
Este método funciona el temporizador. Primero se inicializan los datos:
después se resetea la bandera de evento en la colección de símbolos,
se limpia la lista de eventos en la colección de símbolos y
se establece para la lista la bandera de lista clasificada.
A continuación, obtenemos el siguiente símbolo en un ciclo por todos los símbolos que se encuentran en la lista de símbolos de la colección, actualizamos todos sus datos y comprobamos la presencia de la bandera de evento establecida para el símbolo. Si el evento no existe, pasamos a la comprobación del siguiente símbolo en la colección.
Si en el símbolo se ha establecido la bandera de evento, establecemos la bandera de evento para toda la colección (la presencia de un evento en aunque sea uno de los símbolos conlleva la presencia de un evento para toda la colección). Obtenemos la lista de todos los eventos del símbolo actual, establecemos el código del último evento de la colección igual al código del evento del símbolo actual de la lista, y en el caso de que se dé un evento, se actualizará en el símbolo siguiente el valor guardado en la variable, que almacena el código del último evento de la colección; asimismo obtenemos en un ciclo por la lista de todos los eventos del símbolo actual el siguiente evento y
guardamos el identificador de evento como el último evento en la colección. Exactamente de la misma forma actualizará el evento del símbolo siguiente el último evento de la colección de símbolos.
A continuación, creamos un evento de colección con los parámetros establecidos para él a partir del evento del símbolo( el identificador del evento del símbolo, el parámetro long, el parámetro double y el parámetro string del evento), y guardamos el evento del símbolo en la lista de eventos de la colección de símbolos.
Si guardamos con éxito el evento en la lista de eventos de la colección, este evento se enviará al gráfico del programa con la ayuda de la función EventChartCustom(), con los mismos parámetros de evento para el posterior desarrollo del evento en el programa que realiza la llamada.
De esta forma, tras obtener la lista de eventos de cada uno de los símbolos que se encuentran en la lista de colección, iteramos por la lista de eventos de cada símbolo, e introducimos todos estos eventos en la lista de eventos de colección. Al finalizar el funcionamiento del ciclo, en la lista de eventos de la colección se encontrarán todos los eventos de todos los símbolos de la colección. Para cada uno de los eventos de cada símbolo de la colección se creará un evento de usuario, que será enviado al gráfico del programa de control.
Para reconocer los eventos en la ventana de observación de mercado, vamos a necesitar calcular la suma hash de todos los símbolos que se encuentran en esta. Cualquier cambio en la misma nos indicará que ha sucedido un evento. Lo primero que se nos ocurre es recurrir al cálculo simple del número de símbolos en la ventana, pero... La adición o eliminación de un símbolo aumentará o reducirá el tamaño de la lista, pero la clasificación de los símbolos con el ratón no cambiará el número de símbolos. Esto significa que el número de símbolos en la ventana de "Observación de mercado" no es adecuado para calcular la suma hash.
Nosotros procederemos de la forma siguiente: cada símbolo que se guarda en la lista, su denominación, se puede representar como una cifra (código del símbolo) compuesta de la suma de valores uchar (letras) de los que consta la denominación del símbolo, añadiendo a este valor el índice del símbolo en la lista de la ventana de observación de mercado. Y la suma hash será la suma de todos los códigos de los símbolos.
- La adición de un símbolo a la lista cambiará la suma hash (a la suma hash se le añade el nuevo código del símbolo añadido).
- La eliminación de un símbolo de la lista cambiará la suma hash (a la suma hash se le resta el código del símbolo eliminado).
- La clasificación de la lista de símbolos cambiará la suma hash (cambiarán los códigos de los símbolos clasificados, dado que sus índices cambian)
Implementación del método de trabajo con los eventos de la ventana de "Observación de mercado":
//+------------------------------------------------------------------+ //| Working with market watch window events | //+------------------------------------------------------------------+ void CSymbolsCollection::MarketWatchEventsControl(const bool send_events=true) { ::ResetLastError(); //--- If no current prices are received, exit if(!::SymbolInfoTick(::Symbol(),this.m_tick)) { this.m_global_error=::GetLastError(); return; } uchar array[]; int sum=0; this.m_hash_sum=0; //--- Calculate the hash sum of all visible symbols in the Market Watch window this.m_total_symbols=this.SymbolsTotalVisible(); //--- In the loop by all Market Watch window symbols int total_symbols=::SymbolsTotal(true); for(int i=0;i<total_symbols;i++) { //--- get a symbol name by index string name=::SymbolName(i,true); //--- skip if invisible if(!::SymbolInfoInteger(name,SYMBOL_VISIBLE)) continue; //--- write symbol name (characters) codes to the uchar array ::StringToCharArray(name,array); //--- in a loop by the resulting array, sum up the values of all array cells creating the symbol code for(int j=::ArraySize(array)-1;j>WRONG_VALUE;j--) sum+=array[j]; //--- add the symbol code and the loop index specifying the symbol index in the market watch list to the hash sum m_hash_sum+=i+sum; } //--- If sending events is disabled, create the collection list and exit saving the current hash some as the previous one if(!send_events) { //--- Clear the list this.m_list_all_symbols.Clear(); //--- Clear the collection list this.CreateSymbolsList(true); //--- Clear the market watch window snapshot this.CopySymbolsNames(); //--- save the current hash some as the previous one this.m_hash_sum_prev=this.m_hash_sum; //--- save the current number of visible symbols as the previous one this.m_total_symbol_prev=this.m_total_symbols; return; } //--- If the hash sum of symbols in the Market Watch window has changed if(this.m_hash_sum!=this.m_hash_sum_prev) { //--- Define the Market Watch window event this.m_delta_symbol=this.m_total_symbols-this.m_total_symbol_prev; ENUM_SYMBOL_EVENT event_id= ( this.m_total_symbols>this.m_total_symbol_prev ? SYMBOL_EVENT_MW_ADD : this.m_total_symbols<this.m_total_symbol_prev ? SYMBOL_EVENT_MW_DEL : SYMBOL_EVENT_MW_SORT ); //--- Adding a symbol to the Market Watch window if(event_id==SYMBOL_EVENT_MW_ADD) { string name=""; //--- In the loop by all Market Watch window symbols int total=::SymbolsTotal(true), index=WRONG_VALUE; for(int i=0;i<total;i++) { //--- get the symbol name and check its "visibility". Skip it if invisible name=::SymbolName(i,true); if(!::SymbolInfoInteger(name,SYMBOL_VISIBLE)) continue; //--- If there is no symbol in the collection symbol list yet if(!this.IsPresentSymbolInList(name)) { //--- clear the collection list this.m_list_all_symbols.Clear(); //--- recreate the collection list this.CreateSymbolsList(true); //--- create the symbol collection snapshot this.CopySymbolsNames(); //--- get a new symbol index in the Market Watch window index=this.GetSymbolIndexByName(name); //--- If the "Adding a new symbol" event is successfully added to the event list if(this.EventAdd(event_id,this.TickTime(),index,name)) { //--- send the event to the chart: //--- long value = event time in milliseconds, double value = symbol index, string value = added symbol name ::EventChartCustom(this.m_chart_id,(ushort)event_id,this.TickTime(),index,name); } } } //--- Save the new number of visible symbols in the market watch window this.m_total_symbols=this.SymbolsTotalVisible(); } //--- Remove a symbol from the Market Watch window else if(event_id==SYMBOL_EVENT_MW_DEL) { //--- clear the collection list this.m_list_all_symbols.Clear(); //--- recreate the collection list this.CreateSymbolsList(true); //--- In a loop by the market watch window snapshot int total=this.m_list_names.Total(); for(int i=0; i<total;i++) { //--- get a symbol name string name=this.m_list_names.At(i); if(name==NULL) continue; //--- if no symbol with such a name exists in the collection symbol list if(!this.IsPresentSymbolInList(name)) { //--- If the "Removing a symbol" event is successfully added to the event list if(this.EventAdd(event_id,this.TickTime(),WRONG_VALUE,name)) { //--- send the event to the chart: //--- long value = event tine in milliseconds, double value = -1 for an absent symbol, string value = a removed symbol name ::EventChartCustom(this.m_chart_id,(ushort)event_id,this.TickTime(),WRONG_VALUE,name); } } } //--- Recreate the market watch snapshot this.CopySymbolsNames(); //--- Save the new number of visible symbols in the market watch window this.m_total_symbols=this.SymbolsTotalVisible(); } //--- Sorting symbols in the Market Watch window else if(event_id==SYMBOL_EVENT_MW_SORT) { //--- clear the collection list this.m_list_all_symbols.Clear(); //--- set sorting of the collection list as sorting by index this.m_list_all_symbols.Sort(SORT_BY_SYMBOL_INDEX_MW); //--- recreate the collection list this.CreateSymbolsList(true); //--- get the current symbol index in the Market Watch window int index=this.GetSymbolIndexByName(Symbol()); //--- send the event to the chart: //--- long value = event time in milliseconds, double value = current symbol index, string value = current symbol name ::EventChartCustom(this.m_chart_id,(ushort)event_id,this.TickTime(),index,::Symbol()); } //--- save the current number of visible symbols as the previous one this.m_total_symbol_prev=this.m_total_symbols; //--- save the current hash some as the previous one this.m_hash_sum_prev=this.m_hash_sum; } } //+------------------------------------------------------------------+
Para no explicar todas las ramificaciones del método, hemos destacado por bloques el código en el listado; cada uno de dichos bloques viene acompañado de comentarios detallados. Esperamos que todo resulte comprensible al lector. Cualquier pregunta podrá ser expuesta en los comentarios al artículo.
Al trabajar con la ventana de "Observación de mercado" para monitorear los eventos, no basta con operar solo con la suma hash. Y es que para saber lo que ha sucedido antes de un evento, deberemos tener una copia de la lista de símbolos en la ventana de observación de mercado (plantilla de la observación de mercado), y en función de esta copia, siempre podremos saber, por ejemplo, qué símbolo ha sido eliminado. No existe posibilidad de conocer el nombre del símbolo eliminado si no disponemos de una plantilla de la ventana de observación de mercado.
Método de creación de la plantilla de la ventana de "Observación de mercado":
//+------------------------------------------------------------------+ //| Save names of used Market Watch symbols | //+------------------------------------------------------------------+ void CSymbolsCollection::CopySymbolsNames(void) { this.m_list_names.Clear(); int total=this.m_list_all_symbols.Total(); for(int i=0;i<total;i++) { CSymbol *symbol=this.m_list_all_symbols.At(i); if(symbol==NULL) continue; this.m_list_names.Add(symbol.Name()); } } //+------------------------------------------------------------------+
Aquí: limpiamos la lista de los nombres de los símbolos, obtenemos el símbolo siguiente en el ciclo por la lista de símbolos de la colección y lo añadimos a la lista de nombres de los símbolos.
Al finalizar el ciclo, tendremos una lista con los nombres de todos los símbolos que se encuentran en la lista de la colección de símbolos.
Método que retorna un objeto de símbolo según su nombre:
//+------------------------------------------------------------------+ //| Return an object symbol from the list by a name | //+------------------------------------------------------------------+ CSymbol *CSymbolsCollection::GetSymbolByName(const string name) { CArrayObj *list=this.GetList(SYMBOL_PROP_NAME,name,EQUAL); if(list==NULL || list.Total()==0) return NULL; CSymbol *symbol=list.At(0); return(symbol!=NULL ? symbol : NULL); } //+------------------------------------------------------------------+
Transmitimos el nombre del símbolo al método. A continuación, con la ayuda del método de obtención de la lista de objetos GetList(), creamos una nueva lista según la propiedad "Nombre del símbolo", en la que se deberá encontrar un único objeto de símbolo, con la condición de que su nombre coincida con el nombre transmitido al método.
Obtenemos de esta lista el objeto de símbolo y lo retornamos si la búsqueda finaliza con éxito, o bien retornamos NULL, si no existe un símbolo con este nombre en la lista de la colección de símbolos.
Método que retorna el índice de un símbolo en la lista de colección de símbolos:
//+------------------------------------------------------------------+ //| Return the symbol object index from the list by a name | //+------------------------------------------------------------------+ int CSymbolsCollection::GetSymbolIndexByName(const string name) { int total=this.m_list_all_symbols.Total(); for(int i=0;i<total;i++) { CSymbol *symbol=this.m_list_all_symbols.At(i); if(symbol==NULL) continue; if(symbol.Name()==name) return i; } return WRONG_VALUE; } //+------------------------------------------------------------------+
Aquí: transmitimos al método el nombre del símbolo buscado. A continuación, obtenemos en el ciclo por todos los símbolos que se encuentran en la lista de símbolos el siguiente objeto de símbolo de la lista. Si su nombre coincide con el buscado, retornamos el índice del ciclo. De lo contrario, retornamos -1.
Método que retorna la descripción de un evento en la ventana de "Observación de mercado":
//+------------------------------------------------------------------+ //| Return the Market Watch window event description | //+------------------------------------------------------------------+ string CSymbolsCollection::EventDescription(const ENUM_SYMBOL_EVENT event) { return ( event==SYMBOL_EVENT_MW_ADD ? TextByLanguage("В окно \"Обзор рынка\" добавлен символ","Added symbol to \"Market Watch\" window") : event==SYMBOL_EVENT_MW_DEL ? TextByLanguage("Из окна \"Обзор рынка\" удалён символ","Removed from \"Market Watch\" window") : event==SYMBOL_EVENT_MW_SORT ? TextByLanguage("Изменено расположение символов в окне \"Обзор рынка\"","Changed arrangement of symbols in \"Market Watch\" window") : EnumToString(event) ); } //+------------------------------------------------------------------+
Transmitimos el evento al método, y partiendo del evento que ha sido transmitido, retornamos su descripción de texto.
Método que retorna la descripción del modo de trabajo con los símbolos:
//+------------------------------------------------------------------+ //| Return a description of the mode of working with symbols | //+------------------------------------------------------------------+ string CSymbolsCollection::ModeSymbolsListDescription(void) { return ( this.m_mode_list==SYMBOLS_MODE_CURRENT ? TextByLanguage("Работа только с текущим символом","Work only with current symbol") : this.m_mode_list==SYMBOLS_MODE_DEFINES ? TextByLanguage("Работа с предопределённым списком символов","Work with predefined list of symbols") : this.m_mode_list==SYMBOLS_MODE_MARKET_WATCH ? TextByLanguage("Работа с символами из окна \"Обзор рынка\"","Working with symbols from \"Market Watch\" window") : TextByLanguage("Работа с полным списком всех доступных символов","Work with full list of all available symbols") ); } //+------------------------------------------------------------------+
Aquí, comprobamos el valor de la variable m_mode_list y retornamos la descripción de texto del modo de trabajo de acuerdo con el valor de esta variable.
Con esto, hemos terminado de crear la clase de eventos de símbolo.
Antes de poner en marcha la clase de eventos de símbolo, debemos recordar que en la clase de eventos de cuenta podemos organizar el seguimiento de eventos de la misma forma, ya que ahora tiene el objeto básico CBaseObj; ambos están basados en CBaseObj, y esto significa que ambos pueden utilizar la funcionalidad preparada para buscar eventos. Todos los siguientes objetos que sean herederos de CBaseObj estarán equipados con las mismas propiedades que permiten monitorear los eventos de estos objetos.
Mejorando la clase de eventos de cuenta
Abrimos el archivo de clase de cuenta Account.mqh e introducimos los cambios necesarios.
Sustituimos la inclusión del archivo Object.mqh por la inclusión de BaseObj.mqh:
//+------------------------------------------------------------------+ //| Account.mqh | //| Copyright 2018, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "..\BaseObj.mqh" #include "..\..\Services\DELib.mqh" //+------------------------------------------------------------------+ //| Account class | //+------------------------------------------------------------------+ class CAccount : public CBaseObj { private:
Y ahora, en lugar de la clase CObject, convertiremos a CBaseObj en la clase básica.
Dado que ahora tenemos la posibilidad de asignar una denominación a un objeto heredado de CBaseObj, aprovecharemos esta posibilidad y estableceremos una denominación para el objeto de cuenta.
Añadimos al final del constructor de la clase CAccount una línea que establece el nombre del objeto de cuenta:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CAccount::CAccount(void) { //--- Save integer properties this.m_long_prop[ACCOUNT_PROP_LOGIN] = ::AccountInfoInteger(ACCOUNT_LOGIN); this.m_long_prop[ACCOUNT_PROP_TRADE_MODE] = ::AccountInfoInteger(ACCOUNT_TRADE_MODE); this.m_long_prop[ACCOUNT_PROP_LEVERAGE] = ::AccountInfoInteger(ACCOUNT_LEVERAGE); this.m_long_prop[ACCOUNT_PROP_LIMIT_ORDERS] = ::AccountInfoInteger(ACCOUNT_LIMIT_ORDERS); this.m_long_prop[ACCOUNT_PROP_MARGIN_SO_MODE] = ::AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE); this.m_long_prop[ACCOUNT_PROP_TRADE_ALLOWED] = ::AccountInfoInteger(ACCOUNT_TRADE_ALLOWED); this.m_long_prop[ACCOUNT_PROP_TRADE_EXPERT] = ::AccountInfoInteger(ACCOUNT_TRADE_EXPERT); this.m_long_prop[ACCOUNT_PROP_MARGIN_MODE] = #ifdef __MQL5__::AccountInfoInteger(ACCOUNT_MARGIN_MODE) #else ACCOUNT_MARGIN_MODE_RETAIL_HEDGING #endif ; this.m_long_prop[ACCOUNT_PROP_CURRENCY_DIGITS] = #ifdef __MQL5__::AccountInfoInteger(ACCOUNT_CURRENCY_DIGITS) #else 2 #endif ; this.m_long_prop[ACCOUNT_PROP_SERVER_TYPE] = (::TerminalInfoString(TERMINAL_NAME)=="MetaTrader 5" ? 5 : 4); //--- Save real properties this.m_double_prop[this.IndexProp(ACCOUNT_PROP_BALANCE)] = ::AccountInfoDouble(ACCOUNT_BALANCE); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_CREDIT)] = ::AccountInfoDouble(ACCOUNT_CREDIT); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_PROFIT)] = ::AccountInfoDouble(ACCOUNT_PROFIT); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_EQUITY)] = ::AccountInfoDouble(ACCOUNT_EQUITY); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN)] = ::AccountInfoDouble(ACCOUNT_MARGIN); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_FREE)] = ::AccountInfoDouble(ACCOUNT_MARGIN_FREE); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_LEVEL)] = ::AccountInfoDouble(ACCOUNT_MARGIN_LEVEL); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_CALL)] = ::AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_SO_SO)] = ::AccountInfoDouble(ACCOUNT_MARGIN_SO_SO); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_INITIAL)] = ::AccountInfoDouble(ACCOUNT_MARGIN_INITIAL); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_MARGIN_MAINTENANCE)]=::AccountInfoDouble(ACCOUNT_MARGIN_MAINTENANCE); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_ASSETS)] = ::AccountInfoDouble(ACCOUNT_ASSETS); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_LIABILITIES)] = ::AccountInfoDouble(ACCOUNT_LIABILITIES); this.m_double_prop[this.IndexProp(ACCOUNT_PROP_COMMISSION_BLOCKED)]=::AccountInfoDouble(ACCOUNT_COMMISSION_BLOCKED); //--- Save string properties this.m_string_prop[this.IndexProp(ACCOUNT_PROP_NAME)] = ::AccountInfoString(ACCOUNT_NAME); this.m_string_prop[this.IndexProp(ACCOUNT_PROP_SERVER)] = ::AccountInfoString(ACCOUNT_SERVER); this.m_string_prop[this.IndexProp(ACCOUNT_PROP_CURRENCY)] = ::AccountInfoString(ACCOUNT_CURRENCY); this.m_string_prop[this.IndexProp(ACCOUNT_PROP_COMPANY)] = ::AccountInfoString(ACCOUNT_COMPANY); //--- Account object name this.m_name=TextByLanguage("Счёт ","Account ")+(string)this.Login()+": "+this.Name()+" ("+this.Company()+")"; } //+-------------------------------------------------------------------+
Como podemos ver, el nombre del objeto constará del texto "Cuenta comercial", el número de cuenta, el nombre del cliente y la denominación de la compañía que da servicio a la cuenta.
Por ejemplo, al conectarnos a una de las cuentas comerciales en MetaQuotes-Demo con el nombre del autor, el nombre del objeto de cuenta será el siguiente: "Account 8550475: Artyom Trishkin (MetaQuotes Software Corp.)"
Incluimos en el método de muestra de la denominación breve de la cuenta comercial el valor de la variable names (antes se establecía de la misma forma que hemos establecido el nombre del objeto de cuenta):
//+------------------------------------------------------------------+ //| Display a short account description in the journal | //+------------------------------------------------------------------+ void CAccount::PrintShort(void) { string mode=(this.MarginMode()==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING ? ", Hedge" : this.MarginMode()==ACCOUNT_MARGIN_MODE_EXCHANGE ? ", Exhange" : ""); string names=this.m_name+" "; string values=::DoubleToString(this.Balance(),(int)this.CurrencyDigits())+" "+this.Currency()+", 1:"+(string)+this.Leverage()+mode+", "+this.TradeModeDescription()+" "+this.ServerTypeDescription(); ::Print(names,values); } //+------------------------------------------------------------------+
Estas son todas las mejoras de la clase CAccount.
Ahora vamos a mejorar la clase de la colección de cuenta. Abrimos el archivo AccountsCollection.mqh e introducimos los cambios necesarios.
Hacemos objeto básico de la clase de colección de cuentas la clase CBaseObj:
//+------------------------------------------------------------------+ //| Account collection | //+------------------------------------------------------------------+ class CAccountsCollection : public CBaseObj { private:
Dado que ahora la clase se ha heredado del objeto básico, en el que ya se ha registrado la funcionalidad para monitorear los eventos del objeto, eliminamos de la clase de la colección de cuentas las variables y métodos que han resultado duplicados.
Eliminamos de la estructura de datos de la cuenta el campo de la suma hash:
struct MqlDataAccount { double hash_sum; // Account data hash sum //--- Account integer properties long login; // ACCOUNT_LOGIN (Account number) long leverage; // ACCOUNT_LEVERAGE (Leverage) int limit_orders; // ACCOUNT_LIMIT_ORDERS (Maximum allowed number of active pending orders) bool trade_allowed; // ACCOUNT_TRADE_ALLOWED (Permission to trade for the current account from the server side) bool trade_expert; // ACCOUNT_TRADE_EXPERT (Permission to trade for an EA from the server side) //--- Account real properties double balance; // ACCOUNT_BALANCE (Account balance in a deposit currency) double credit; // ACCOUNT_CREDIT (Credit in a deposit currency) double profit; // ACCOUNT_PROFIT (Current profit on an account in the account currency) double equity; // ACCOUNT_EQUITY (Equity on an account in the deposit currency) double margin; // ACCOUNT_MARGIN (Reserved margin on an account in a deposit currency) double margin_free; // ACCOUNT_MARGIN_FREE (Free funds available for opening a position in a deposit currency) double margin_level; // ACCOUNT_MARGIN_LEVEL (Margin level on an account in %) double margin_so_call; // ACCOUNT_MARGIN_SO_CALL (MarginCall) double margin_so_so; // ACCOUNT_MARGIN_SO_SO (StopOut) double margin_initial; // ACCOUNT_MARGIN_INITIAL (Funds reserved on an account to ensure a guarantee amount for all pending orders) double margin_maintenance; // ACCOUNT_MARGIN_MAINTENANCE (Funds reserved on an account to ensure a minimum amount for all open positions) double assets; // ACCOUNT_ASSETS (Current assets on an account) double liabilities; // ACCOUNT_LIABILITIES (Current liabilities on an account) double comission_blocked; // ACCOUNT_COMMISSION_BLOCKED (Current sum of blocked commissions on an account) };
Eliminamos las variables de miembro privadas de la clase:
MqlTick m_tick; // Tick structure string m_symbol; // Current symbol long m_chart_id; // Control program chart ID CListObj m_list_accounts; // Account object list CArrayInt m_list_changes; // Account change list string m_folder_name; // Name of a folder account objects are stored int m_index_current; // Index of an account object featuring the current account data //--- Tracking account changes bool m_is_account_event; // Account data event flag int m_change_code; // Account change code
Renombramos el método SetChangeCode() como SetEventCode(), para que los nombres de los métodos con el mismo tipo sean los mismos en clases diferentes.
Hacemos el método SetTypeEvent() virtual, dado que ya ha sido declarado en la clase CBaseObj, y debe implementarse en los herederos.
Eliminamos el método IsPresentEventFlag() de la clase, ya ha sido implementado en CBaseObj.
Asimismo, cribamos un poco los métodos duplicados en la sección pública de la clase.
Eliminamos los métodos GetEventCode(), GetListChanges() y SetChartID(), y hacemos el método ENUM_ACCOUNT_EVENT GetEvent(const int shift=WRONG_VALUE) de la forma siguiente:
ENUM_ACCOUNT_EVENT GetEventID(const int shift=WRONG_VALUE,const bool check_out=true);
Y analizamos de inmediato su implementación fuera del cuerpo de la clase:
//+------------------------------------------------------------------+ //| Return the account event by its number in the list | //+------------------------------------------------------------------+ ENUM_ACCOUNT_EVENT CAccountsCollection::GetEventID(const int shift=WRONG_VALUE,const bool check_out=true) { CEventBaseObj *event=this.GetEvent(shift,check_out); if(event==NULL) return ACCOUNT_EVENT_NO_EVENT; return (ENUM_ACCOUNT_EVENT)event.ID(); } //+------------------------------------------------------------------+
Transmitimos al método el índice del evento buscado (-1 para seleccionar el último) y la bandera de control de la salida del índice fuera del tamaño límite de la lista de eventos.
Obtenemos el objeto de evento con la ayuda del método del objeto básico CBaseObj GetEvent(), analizado por nosotros al inicio del artículo. Si no ha habido evento, retornamos "No hay evento", de lo contrario, retornamos el identificador del evento.
Eliminamos en la lista de inicialización en el constructor de la clase la inicialización de todos los parámetros excepto el establecimiento del símbolo y establecemos el nombre de la subcarpeta para guardar los archivos de los objetos de cuenta:
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CAccountsCollection::CAccountsCollection(void) : m_symbol(::Symbol()) { this.m_list_accounts.Clear(); this.m_list_accounts.Sort(SORT_BY_ACCOUNT_LOGIN); this.m_list_accounts.Type(COLLECTION_ACCOUNT_ID); ::ZeroMemory(this.m_struct_prev_account); ::ZeroMemory(this.m_tick); this.InitChangesParams(); this.InitControlsParams(); //--- Create the folder for storing account files this.SetSubFolderName("Accounts"); ::ResetLastError(); if(!::FolderCreate(this.m_folder_name,FILE_COMMON)) ::Print(DFUN,TextByLanguage("Не удалось создать папку хранения файлов. Ошибка ","Could not create file storage folder. Error "),::GetLastError()); //--- Create the current account object and add it to the list CAccount* account=new CAccount(); if(account!=NULL) { if(!this.AddToList(account)) { ::Print(DFUN_ERR_LINE,TextByLanguage("Ошибка. Не удалось добавить текущий объект-аккаунт в список-коллекцию.","Error. Failed to add current account object to collection list.")); delete account; } else account.PrintShort(); } else ::Print(DFUN,TextByLanguage("Ошибка. Не удалось создать объект-аккаунт с данными текущего счёта.","Error. Failed to create an account object with current account data.")); //--- Download account objects from the files to the collection this.LoadObjects(); //--- Save the current account index this.m_index_current=this.Index(); } //+------------------------------------------------------------------+
Hacemos el método de actualización de los datos de la cuenta Refresh() virtual, dado que se declara en la clase CBaseObj y se implementa en sus herederos.
En la implementación del método se han introducido ciertos cambios:
//+------------------------------------------------------------------+ //| Update the current account data | //+------------------------------------------------------------------+ void CAccountsCollection::Refresh(void) { ::ResetLastError(); if(!::SymbolInfoTick(::Symbol(),this.m_tick)) { this.m_global_error=::GetLastError(); return; } if(this.m_index_current==WRONG_VALUE) return; CAccount* account=this.m_list_accounts.At(this.m_index_current); if(account==NULL) return; //--- Prepare event data this.m_is_event=false; ::ZeroMemory(this.m_struct_curr_account); this.m_hash_sum=0; this.SetAccountsParams(account); //--- First launch if(!this.m_struct_prev_account.login) { this.m_struct_prev_account=this.m_struct_curr_account; this.m_hash_sum_prev=this.m_hash_sum; return; } //--- If the account hash sum changed if(this.m_hash_sum!=this.m_hash_sum_prev) { this.m_list_events.Clear(); this.m_event_code=this.SetEventCode(); this.SetTypeEvent(); int total=this.m_list_events.Total(); if(total>0) { this.m_is_event=true; for(int i=0;i<total;i++) { CEventBaseObj *event=this.GetEvent(i,false); if(event==NULL) continue; ENUM_ACCOUNT_EVENT event_id=(ENUM_ACCOUNT_EVENT)event.ID(); if(event_id==ACCOUNT_EVENT_NO_EVENT) continue; long lparam=event.LParam(); double dparam=event.DParam(); string sparam=event.SParam(); ::EventChartCustom(this.m_chart_id,(ushort)event_id,lparam,dparam,sparam); } } this.m_hash_sum_prev=this.m_hash_sum; } } //+------------------------------------------------------------------+
Vamos a analizar solo los cambios introducidos.
Primero, obtenemos los datos de cotización del símbolo (para determinar la hora en milisegundos), y si no hemos logrado obtenerlos, salimos del método.
Reseteamos la bandera de evento de la cuenta y el valor de la suma hash actual. En el primer inicio, guardamos la suma hash actual como pasada.
Cuando cambia la suma hash, limpiamos la lista de eventos de la cuenta y realizamos exactamente las mismas acciones para obtener los eventos de la lista de eventos de la cuenta, que ya realizamos al obtener la lista de eventos de los símbolos, y que analizamos anteriormente.
Ahora, para cualquier objeto heredado de CBaseObj, las acciones destinadas a obtener sus eventos serán idénticas. Por eso, será mejor que nos familiaricemos de nuevo con su obtención, que ya hemos analizado en este artículo, para que todo resulte comprensible en artículos posteriores y no tengamos que regresar al análisis de las acciones realizadas al obtener la lista de eventos de un objeto.
Sustituimos en el objeto de cuenta y la estructura de datos de la cuenta en el método de guardado de las propiedades de la cuenta la variable de clase CBaseObj de la suma hash y guardamos el nombre del objeto:
//+------------------------------------------------------------------+ //| Write the current account data to the account object properties | //+------------------------------------------------------------------+ void CAccountsCollection::SetAccountsParams(CAccount *account) { if(account==NULL) return; //--- Name this.m_name=account.GetName(); //--- Account number this.m_struct_curr_account.login=account.Login(); //--- Leverage account.SetProperty(ACCOUNT_PROP_LEVERAGE,::AccountInfoInteger(ACCOUNT_LEVERAGE)); this.m_struct_curr_account.leverage=account.Leverage(); this.m_hash_sum+=(double)this.m_struct_curr_account.leverage; //--- Maximum allowed number of active pending orders account.SetProperty(ACCOUNT_PROP_LIMIT_ORDERS,::AccountInfoInteger(ACCOUNT_LIMIT_ORDERS)); this.m_struct_curr_account.limit_orders=(int)account.LimitOrders(); this.m_hash_sum+=(double)this.m_struct_curr_account.limit_orders; //--- Permission to trade for the current account from the server side account.SetProperty(ACCOUNT_PROP_TRADE_ALLOWED,::AccountInfoInteger(ACCOUNT_TRADE_ALLOWED)); this.m_struct_curr_account.trade_allowed=account.TradeAllowed(); this.m_hash_sum+=(double)this.m_struct_curr_account.trade_allowed; //--- Permission to trade for an EA from the server side account.SetProperty(ACCOUNT_PROP_TRADE_EXPERT,::AccountInfoInteger(ACCOUNT_TRADE_EXPERT)); this.m_struct_curr_account.trade_expert=account.TradeExpert(); this.m_hash_sum+=(double)this.m_struct_curr_account.trade_expert; //--- Account balance in a deposit currency account.SetProperty(ACCOUNT_PROP_BALANCE,::AccountInfoDouble(ACCOUNT_BALANCE)); this.m_struct_curr_account.balance=account.Balance(); this.m_hash_sum+=(double)this.m_struct_curr_account.balance; //--- Credit in a deposit currency account.SetProperty(ACCOUNT_PROP_CREDIT,::AccountInfoDouble(ACCOUNT_CREDIT)); this.m_struct_curr_account.credit=account.Credit(); this.m_hash_sum+=(double)this.m_struct_curr_account.credit; //--- Current profit on an account in the account currency account.SetProperty(ACCOUNT_PROP_PROFIT,::AccountInfoDouble(ACCOUNT_PROFIT)); this.m_struct_curr_account.profit=account.Profit(); this.m_hash_sum+=(double)this.m_struct_curr_account.profit; //--- Equity on an account in the deposit currency account.SetProperty(ACCOUNT_PROP_EQUITY,::AccountInfoDouble(ACCOUNT_EQUITY)); this.m_struct_curr_account.equity=account.Equity(); this.m_hash_sum+=(double)this.m_struct_curr_account.equity; //--- Reserved margin on an account in the deposit currency account.SetProperty(ACCOUNT_PROP_MARGIN,::AccountInfoDouble(ACCOUNT_MARGIN)); this.m_struct_curr_account.margin=account.Margin(); this.m_hash_sum+=(double)this.m_struct_curr_account.margin; //--- Free funds available for opening a position on an account in the deposit currency account.SetProperty(ACCOUNT_PROP_MARGIN_FREE,::AccountInfoDouble(ACCOUNT_MARGIN_FREE)); this.m_struct_curr_account.margin_free=account.MarginFree(); this.m_hash_sum+=(double)this.m_struct_curr_account.margin_free; //--- Margin level on an account in % account.SetProperty(ACCOUNT_PROP_MARGIN_LEVEL,::AccountInfoDouble(ACCOUNT_MARGIN_LEVEL)); this.m_struct_curr_account.margin_level=account.MarginLevel(); this.m_hash_sum+=(double)this.m_struct_curr_account.margin_level; //--- Margin Call level account.SetProperty(ACCOUNT_PROP_MARGIN_SO_CALL,::AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL)); this.m_struct_curr_account.margin_so_call=account.MarginSOCall(); this.m_hash_sum+=(double)this.m_struct_curr_account.margin_so_call; //--- Stop Out level account.SetProperty(ACCOUNT_PROP_MARGIN_SO_SO,::AccountInfoDouble(ACCOUNT_MARGIN_SO_SO)); this.m_struct_curr_account.margin_so_so=account.MarginSOSO(); this.m_hash_sum+=(double)this.m_struct_curr_account.margin_so_so; //--- Funds reserved on an account to ensure a guarantee amount for all pending orders account.SetProperty(ACCOUNT_PROP_MARGIN_INITIAL,::AccountInfoDouble(ACCOUNT_MARGIN_INITIAL)); this.m_struct_curr_account.margin_initial=account.MarginInitial(); this.m_hash_sum+=(double)this.m_struct_curr_account.margin_initial; //--- Funds reserved on an account to ensure a minimum amount for all open positions account.SetProperty(ACCOUNT_PROP_MARGIN_MAINTENANCE,::AccountInfoDouble(ACCOUNT_MARGIN_MAINTENANCE)); this.m_struct_curr_account.margin_maintenance=account.MarginMaintenance(); this.m_hash_sum+=(double)this.m_struct_curr_account.margin_maintenance; //--- Current assets on an account account.SetProperty(ACCOUNT_PROP_ASSETS,::AccountInfoDouble(ACCOUNT_ASSETS)); this.m_struct_curr_account.assets=account.Assets(); this.m_hash_sum+=(double)this.m_struct_curr_account.assets; //--- Current liabilities on an account account.SetProperty(ACCOUNT_PROP_LIABILITIES,::AccountInfoDouble(ACCOUNT_LIABILITIES)); this.m_struct_curr_account.liabilities=account.Liabilities(); this.m_hash_sum+=(double)this.m_struct_curr_account.liabilities; //--- Current sum of blocked commissions on an account account.SetProperty(ACCOUNT_PROP_COMMISSION_BLOCKED,::AccountInfoDouble(ACCOUNT_COMMISSION_BLOCKED)); this.m_struct_curr_account.comission_blocked=account.ComissionBlocked(); this.m_hash_sum+=(double)this.m_struct_curr_account.comission_blocked; } //+------------------------------------------------------------------+
Hemos mejorado y modificado de la misma forma el método SetTypeEvent() de la clase de colección de cuentas, debido a que ahora es posible determinar los eventos de cualquier objeto. El método es voluminoso, pero todas las acciones para determinar los tipos de evento de la cuenta son del mismo tipo, y ya han sido analizadas aquí al estudiar cómo se determinan los tipos de evento de los símbolos. Por eso, solo vamos a mostrar un ejemplo sobre, la definición del evento que permite el comercio en la cuenta comercial. Podrá encontrar el listado completo del método en los archivos adjuntos al artículo:
//+------------------------------------------------------------------+ //| Set the account object event type | //+------------------------------------------------------------------+ void CAccountsCollection::SetTypeEvent(void) { this.InitChangesParams(); ENUM_ACCOUNT_EVENT event_id=ACCOUNT_EVENT_NO_EVENT; //--- Changing permission to trade for the account if(this.IsPresentEventFlag(ACCOUNT_EVENT_FLAG_TRADE_ALLOWED)) { if(!this.m_struct_curr_account.trade_allowed) { this.m_is_change_trade_allowed_off=true; event_id=ACCOUNT_EVENT_TRADE_ALLOWED_OFF; if(this.EventAdd(event_id,this.TickTime(),this.m_is_change_trade_allowed_off,this.m_name)) this.m_struct_prev_account.trade_allowed=this.m_struct_curr_account.trade_allowed; } else { this.m_is_change_trade_allowed_on=true; event_id=ACCOUNT_EVENT_TRADE_ALLOWED_ON; if(this.EventAdd(event_id,this.TickTime(),this.m_is_change_trade_allowed_on,this.m_name)) this.m_struct_prev_account.trade_allowed=this.m_struct_curr_account.trade_allowed; } } //--- Changing permission for auto trading for the account
Con esto, podemos considerar finalizados la modificación y mejora de la clase de colección de cuentas, por lo que vamos a activar la clase actualizada de evento de símbolo y la clase de cuenta.
Como recordaremos, el control parte desde la clase CEngine, por lo que todos los datos se envían a esta. La clase de evento de símbolo y la clase de cuenta no son una excepción.
Activando la clase de eventos de símbolo y la clase actualizada de la cuenta para el trabajo
Abrimos el archivo Engine.mqh e introducimos los cambios y correcciones necesarias.
En la sección privada de la clase, declaramos la bandera de evento de símbolo y el valor del último evento en el símbolo:
//+------------------------------------------------------------------+ //| Library basis class | //+------------------------------------------------------------------+ class CEngine : public CObject { private: CHistoryCollection m_history; // Collection of historical orders and deals CMarketCollection m_market; // Collection of market orders and deals CEventsCollection m_events; // Event collection CAccountsCollection m_accounts; // Account collection CSymbolsCollection m_symbols; // Symbol collection CArrayObj m_list_counters; // List of timer counters int m_global_error; // Global error code bool m_first_start; // First launch flag bool m_is_hedge; // Hedge account flag bool m_is_tester; // Flag of working in the tester bool m_is_market_trade_event; // Account trading event flag bool m_is_history_trade_event; // Account history trading event flag bool m_is_account_event; // Account change event flag bool m_is_symbol_event; // Symbol change event flag ENUM_TRADE_EVENT m_last_trade_event; // Last account trading event ENUM_ACCOUNT_EVENT m_last_account_event; // Last event in the account properties ENUM_SYMBOL_EVENT m_last_symbol_event; // Last event in the symbol properties //--- Return the counter index by id
En la sección pública de la clase, declaramos el método que retorna la descripción del último evento comercial:
//--- Return the list of historical (1) orders, (2) removed pending orders, (3) deals, //--- (4) all market orders of a position by its ID, (5) description of the last trading event CArrayObj *GetListHistoryOrders(void); CArrayObj *GetListHistoryPendings(void); CArrayObj *GetListDeals(void); CArrayObj *GetListAllOrdersByPosID(const ulong position_id); string GetLastTradeEventDescription(void);
y los nuevos métodos necesarios para trabajar con los eventos de símbolo, además de cambiar el método que retorna la bandera de evento de cuenta:
//--- Return the list of (1) used symbols, (2) symbol events, (3) the last symbol change event //--- (4) the current symbol, (5) symbol event description, (6) Market Watch event description CArrayObj *GetListAllUsedSymbols(void) { return this.m_symbols.GetList(); } CArrayObj *GetListSymbolsEvents(void) { return this.m_symbols.GetListEvents(); } ENUM_SYMBOL_EVENT GetLastSymbolsEvent() { return this.m_symbols.GetLastEvent(); } CSymbol *GetSymbolCurrent(void); string GetSymbolEventDescription(ENUM_SYMBOL_EVENT event); string GetMWEventDescription(ENUM_SYMBOL_EVENT event) { return this.m_symbols.EventDescription(event); } string ModeSymbolsListDescription(void) { return this.m_symbols.ModeSymbolsListDescription(); } //--- Return the list of order, deal and position events CArrayObj *GetListAllOrdersEvents(void) { return this.m_events.GetList(); } //--- Reset the last trading event void ResetLastTradeEvent(void) { this.m_events.ResetLastTradeEvent(); } //--- Return the (1) last trading event, (2) the last event in the account properties, (3) hedging account flag, (4) flag of working in the tester ENUM_TRADE_EVENT LastTradeEvent(void) const { return this.m_last_trade_event; } ENUM_ACCOUNT_EVENT LastAccountEvent(void) const { return this.m_last_account_event; } ENUM_SYMBOL_EVENT LastSymbolsEvent(void) const { return this.m_last_symbol_event; } //--- Return the (1) hedge account, (2) working in the tester, (3) account event and (4) symbol event flag bool IsHedge(void) const { return this.m_is_hedge; } bool IsTester(void) const { return this.m_is_tester; } bool IsAccountsEvent(void) const { return this.m_accounts.IsEvent(); } bool IsSymbolsEvent(void) const { return this.m_symbols.IsEvent(); } //--- Return the (1) symbol object by name, as well as the code of the last event of (2) an account and (3) a symbol CSymbol *GetSymbolObjByName(const string name) { return this.m_symbols.GetSymbolByName(name); } int GetAccountEventsCode(void) const { return this.m_accounts.GetEventCode(); } int GetSymbolsEventsCode(void) const { return this.m_symbols.GetLastEventsCode(); } //--- Return the number of (1) symbols, (2) events in the symbol collection int GetSymbolsCollectionTotal(void) const { return this.m_symbols.GetSymbolsCollectionTotal(); } int GetSymbolsCollectionEventsTotal(void) const { return this.m_symbols.GetEventsTotal(); }
En la lista de inicialización del constructor de la clase, añadimos la inicialización del último evento en la colección de símbolos:
//+------------------------------------------------------------------+ //| CEngine constructor | //+------------------------------------------------------------------+ CEngine::CEngine() : m_first_start(true), m_last_trade_event(TRADE_EVENT_NO_EVENT), m_last_account_event(ACCOUNT_EVENT_NO_EVENT), m_last_symbol_event(SYMBOL_EVENT_NO_EVENT), m_global_error(ERR_SUCCESS) { this.m_is_hedge=#ifdef __MQL4__ true #else bool(::AccountInfoInteger(ACCOUNT_MARGIN_MODE)==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING) #endif; this.m_is_tester=::MQLInfoInteger(MQL_TESTER); this.m_list_counters.Sort(); this.m_list_counters.Clear(); this.CreateCounter(COLLECTION_ORD_COUNTER_ID,COLLECTION_ORD_COUNTER_STEP,COLLECTION_ORD_PAUSE); this.CreateCounter(COLLECTION_ACC_COUNTER_ID,COLLECTION_ACC_COUNTER_STEP,COLLECTION_ACC_PAUSE); this.CreateCounter(COLLECTION_SYM_COUNTER_ID1,COLLECTION_SYM_COUNTER_STEP1,COLLECTION_SYM_PAUSE1); this.CreateCounter(COLLECTION_SYM_COUNTER_ID2,COLLECTION_SYM_COUNTER_STEP2,COLLECTION_SYM_PAUSE2); ::ResetLastError(); #ifdef __MQL5__ if(!::EventSetMillisecondTimer(TIMER_FREQUENCY)) { ::Print(DFUN_ERR_LINE,"Не удалось создать таймер. Ошибка: ","Could not create timer. Error: ",(string)::GetLastError()); this.m_global_error=::GetLastError(); } //---__MQL4__ #else if(!this.IsTester() && !::EventSetMillisecondTimer(TIMER_FREQUENCY)) { ::Print(DFUN_ERR_LINE,"Не удалось создать таймер. Ошибка: ","Could not create timer. Error: ",(string)::GetLastError()); this.m_global_error=::GetLastError(); } #endif } //+------------------------------------------------------------------+
Introducimos la correcciones en el manejador del temporizador de la clase, en los bloques de procesamiento temporizador1 y temporizador2 de la colección de símbolos:
//+------------------------------------------------------------------+ //| CEngine timer | //+------------------------------------------------------------------+ void CEngine::OnTimer(void) { //--- Timer of the collections of historical orders and deals, as well as of market orders and positions int index=this.CounterIndex(COLLECTION_ORD_COUNTER_ID); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- If this is not a tester if(!this.IsTester()) { //--- If unpaused, work with the order, deal and position collections events if(counter.IsTimeDone()) this.TradeEventsControl(); } //--- If this is a tester, work with collection events by tick else this.TradeEventsControl(); } } //--- Account collection timer index=this.CounterIndex(COLLECTION_ACC_COUNTER_ID); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- If this is not a tester if(!this.IsTester()) { //--- If unpaused, work with the account collection events if(counter.IsTimeDone()) this.AccountEventsControl(); } //--- If this is a tester, work with collection events by tick else this.AccountEventsControl(); } } //--- Timer 1 of the symbol collection (updating symbol quote data in the collection) index=this.CounterIndex(COLLECTION_SYM_COUNTER_ID1); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- If this is not a tester if(!this.IsTester()) { //--- If the pause is over, update quote data of all symbols in the collection if(counter.IsTimeDone()) this.m_symbols.RefreshRates(); } //--- In case of a tester, update quote data of all collection symbols by tick else this.m_symbols.RefreshRates(); } } //--- Timer 2 of the symbol collection (updating all data of all symbols in the collection and tracking symbl and symbol search events in the market watch window) index=this.CounterIndex(COLLECTION_SYM_COUNTER_ID2); if(index>WRONG_VALUE) { CTimerCounter* counter=this.m_list_counters.At(index); if(counter!=NULL) { //--- If this is not a tester if(!this.IsTester()) { //--- If the pause is over if(counter.IsTimeDone()) { //--- update data and work with events of all symbols in the collection this.SymbolEventsControl(); //--- When working with the market watch list, check the market watch window events if(this.m_symbols.ModeSymbolsList()==SYMBOLS_MODE_MARKET_WATCH) this.MarketWatchEventsControl(); } } //--- If this is a tester, work with events of all symbols in the collection by tick else this.SymbolEventsControl(); } } } //+------------------------------------------------------------------+
Aquí, cuando finaliza el contador del temporizador1, debemos simplemente actualizar los datos de cotización de todos los símbolos de la colección, por eso, llamamos al método RefreshRates() de la colección de símbolos.
Cuando finaliza el contador del temporizador2, tenemos que actualizar por completo todos los símbolos de la colección de símbolos y monitorear los eventos sucedidos tanto de los símbolos de la colección, como de la lista de símbolos en la ventana de "Observación de mercado", por eso, llamamos a los métodos de la clase CEngine SymbolEventsControl(), y solo al trabajar en el simulador, MarketWatchEventsControl().
Implementación del método de trabajo con los eventos de la colección de símbolos:
//+------------------------------------------------------------------+ //| Working with symbol collection events | //+------------------------------------------------------------------+ void CEngine::SymbolEventsControl(void) { this.m_symbols.SymbolsEventsControl(); this.m_is_symbol_event=this.m_symbols.IsEvent(); //--- If there are changes in symbol properties if(this.m_is_symbol_event) { //--- Get the last event of the symbol property change this.m_last_symbol_event=this.m_symbols.GetLastEvent(); } } //+------------------------------------------------------------------+
Aquí: llamamos al método de la colección de símbolos SymbolsEventsControl(), analizado en este artículo al estudiar la clase de eventos de la colección de símbolos. Cuando este método termina de funcionar, la bandera de evento se activará en la clase de la colección de símbolos, con la condición de que un evento haya sido registrado en cualquiera de los símbolos de la colección; luego registraremos el estado de esta bandera con la ayuda del método IsEvent() de la clase del objeto básico CBaseObj en la variable de bandera del evento de la colección de símbolos m_is_symbol_event, cuyo valor se puede monitorear en el programa que realiza la llamada. Si se ha registrado un evento en la colección de símbolos, registramos el último evento en la variable m_last_symbol_event, cuyo valor también se puede monitorear en el programa que realiza la llamada.
Implementación del método de trabajo con los eventos de la ventana de "Observación de mercado":
//+------------------------------------------------------------------+ //| Working with symbol list events in the market watch window | //+------------------------------------------------------------------+ void CEngine::MarketWatchEventsControl(void) { if(this.IsTester()) return; this.m_symbols.MarketWatchEventsControl(); } //+------------------------------------------------------------------+
Aquí, si se trata del simulador, salimos, de lo contrario, llamamos al método MarketWatchEventsControl() de la clase de colección de símbolos para procesar los eventos de la ventana de observación de mercado, que analizamos antes al estudiar el seguimiento de los eventos de la clase de colección de símbolos.
Implementación del método que retorna la descripción del último evento comercial:
//+------------------------------------------------------------------+ //| Return the description of the last trading event | //+------------------------------------------------------------------+ string CEngine::GetLastTradeEventDescription(void) { CArrayObj *list=this.m_events.GetList(); if(list!=NULL) { if(list.Total()==0) return TextByLanguage("С момента последнего запуска ЕА торговых событий не было","There have been no trade events since the last launch of EA"); CEvent *event=list.At(list.Total()-1); if(event!=NULL) return event.TypeEventDescription(); } return DFUN_ERR_LINE+TextByLanguage("Не удалось получить описание последнего торгового события","Failed to get the description of the last trading event"); } //+------------------------------------------------------------------+
Aquí, obtenemos la lista completa de eventos comerciales en la cuenta. Si hemos obtenido la lista, pero su valor es cero, retornamos un mensaje indicando que no hemos tenido eventos comerciales, de lo contrario, obtenemos de la lista el último evento y retornamos su descripción. En el caso contrario, retornamos un mensaje sobre el fallo al obtener el evento comercial.
Método que retorna la descripción del último evento en la colección de símbolos:
//+------------------------------------------------------------------+ //| Return the symbol event description | //+------------------------------------------------------------------+ string CEngine::GetSymbolEventDescription(ENUM_SYMBOL_EVENT event) { CArrayObj *list=this.m_symbols.GetList(); if(list!=NULL) { if(list.Total()==0) return TextByLanguage("С момента последнего запуска ЕА не было никаких событий символов","There have been no events of symbols since the last launch of EA"); CSymbol *symbol=list.At(list.Total()-1); if(symbol!=NULL) return symbol.EventDescription(event); } return DFUN_ERR_LINE+TextByLanguage("Не удалось получить описание события символа","Failed to get symbol's event description"); } //+------------------------------------------------------------------+
El método funciona de forma idéntica al método de retorno de la descripción del último evento comercial que acabamos de analizar.
Ya hemos terminado las mejoras de la clase CEngine, y lo tenemos todo listo para simular los eventos de símbolo, la clase de cuenta actualizada y los eventos de cuenta.
Hemos introducido en las clases analizadas algunos cambios que no se reflejan en el artículo, dado que se trata solo de cambios, por ejemplo, relacionados con las denominaciones de algunos métodos, para que los métodos del mismo tipo y de diferentes clases tengan los mismos nombres dentro de lo posible. Estas pequeñas mejoras no serán mencionadas en el código de la biblioteca, ya que esta se encuentra en constante modificación: el lector siempre podrá familiarizarse con los cambios en los archivos adjuntos a los artículos.
Simulando los eventos de símbolo y cuenta
Para poner a prueba la colección, vamos a tomar el asesor de prueba del artículo anterior, guardarlo con el nombre \MQL5\Experts\TestDoEasy\ Part16\TestDoEasyPart16.mq5 e introducir en el mismo los cambios necesarios.
Añadimos a la lista de variables globales la variable para guardar el modo de trabajo con las listas de símbolos:
//--- global variables CEngine engine; #ifdef __MQL5__ CTrade trade; #endif SDataButt butt_data[TOTAL_BUTT]; string prefix; double lot; double withdrawal=(InpWithdrawal<0.1 ? 0.1 : InpWithdrawal); ulong magic_number; uint stoploss; uint takeprofit; uint distance_pending; uint distance_stoplimit; uint slippage; bool trailing_on; double trailing_stop; double trailing_step; uint trailing_start; uint stoploss_to_modify; uint takeprofit_to_modify; int used_symbols_mode; string used_symbols; string array_used_symbols[];
Dado que al elegir el modo de trabajo con los símbolos "Trabajo con la lista completa de símbolos en el servidor", el primer inicio puede resultar bastante prolongado (porque la colección de símbolos debe recopilar todos los datos sobre todos los símbolos disponibles), vamos a necesitar advertir de ello al usuario. No tiene sentido hacer esto en la propia biblioteca, puesto que esta solo debe procesar lo que le pide el usuario, por eso, implementaremos la advertencia en el manejador OnInit() del programa.
Lo haremos así: si en los ajustes del asesor se selecciona el modo de trabajo con la lista completa de símbolos disponibles en el servidor, el programa mostrará la ventana estándar de la función MessageBox() con la advertencia
proponiendo seleccionar "Sí" para cargar la lista completa de símbolos, o "No" para trabajar solo con el símbolo actual. El usuario solo tiene que elegir: pulsar "Sí" y esperar a que se cree la colección de todos los símbolos disponibles, o bien pulsar "No" y trabajar con el actual.
Implementamos la amplia comprobación, mostrando al usuario la pregunta en el manejador OnInit() del asesor:
//--- Check if working with the full list is selected used_symbols_mode=InpModeUsedSymbols; if((ENUM_SYMBOLS_MODE)used_symbols_mode==SYMBOLS_MODE_ALL) { int total=SymbolsTotal(false); string ru_n="\nКоличество символов на сервере "+(string)total+".\nМаксимальное количество: "+(string)SYMBOLS_COMMON_TOTAL+" символов."; string en_n="\nThe number of symbols on server "+(string)total+".\nMaximal number: "+(string)SYMBOLS_COMMON_TOTAL+" symbols."; string caption=TextByLanguage("Внимание!","Attention!"); string ru="Выбран режим работы с полным списком.\nВ этом режиме первичная подготовка списка коллекции символов может занять длительное время."+ru_n+"\nПродолжить?\n\"Нет\" - работа с текущим символом \""+Symbol()+"\""; string en="Full list mode selected.\nIn this mode, the initial preparation of the collection symbols list may take a long time."+en_n+"\nContinue?\n\"No\" - working with the current symbol \""+Symbol()+"\""; string message=TextByLanguage(ru,en); int flags=(MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2); int mb_res=MessageBox(message,caption,flags); switch(mb_res) { case IDNO : used_symbols_mode=SYMBOLS_MODE_CURRENT; break; default: break; } }
Aquí, asignamos a la variable global used_symbols_mode el valor del modo de trabajo con los símbolos seleccionado por el usuario en los ajustes del asesor.
Si se ha seleccionado el modo de trabajo con la lista completa, creamos el texto del mensaje de la ventana de advertencia y mostramos esta ventana en la pantalla. A continuación, comprobamos qué botón ha pulsado el usuario. Si se trata del botón "No", asignamos a la variable used_symbols_mode el valor del modo de trabajo con el símbolo actual.
En el resto de los casos (botón "Sí" o Esc), dejamos el modo de trabajo con la lista completa de símbolos disponibles.
Acto seguido, creamos una matriz con los símbolos usados (enviamos a la función de creación de la matriz la variable used_symbols_mode):
//--- Fill in the array of used symbols used_symbols=InpUsedSymbols; CreateUsedSymbolsArray((ENUM_SYMBOLS_MODE)used_symbols_mode,used_symbols,array_used_symbols);
establecemos en la biblioteca el tipo de lista utilizado (modo de trabajo con los símbolos) y mostramos en el diario un mensaje sobre el modo usado de trabajo con los símbolos:
//--- Set the type of the used symbol list in the symbol collection engine.SetUsedSymbols(array_used_symbols); //--- Displaying the selected mode of working with the symbol object collection Print(engine.ModeSymbolsListDescription(),TextByLanguage(". Количество используемых символов: ",". Number of symbols used: "),engine.GetSymbolsCollectionTotal());
Eliminamos el bloque de código de comprobación rápida de la colección de símbolos del manejador OnInit(), ya que no resulta necesario en este asesor de prueba:
//--- Fast check of the symbol object collection
CArrayObj *list=engine.GetListAllUsedSymbols();
CSymbol *symbol=NULL;
if(list!=NULL)
{
int total=list.Total();
for(int i=0;i<total;i++)
{
symbol=list.At(i);
if(symbol==NULL)
continue;
symbol.Refresh();
symbol.RefreshRates();
symbol.PrintShort();
if(InpModeUsedSymbols<SYMBOLS_MODE_MARKET_WATCH)
symbol.Print();
}
}
Añadimos al manejador OnTick() una variable para guardar el último evento en la colección de símbolos y escribimos (o modificamos, para los eventos de cuenta) el bloque de procesamiento de los eventos de cuenta y de los eventos de la colección de símbolos:
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- Initializing the last events static ENUM_TRADE_EVENT last_trade_event=WRONG_VALUE; static ENUM_ACCOUNT_EVENT last_account_event=WRONG_VALUE; static ENUM_SYMBOL_EVENT last_symbol_event=WRONG_VALUE; //--- If working in the tester if(MQLInfoInteger(MQL_TESTER)) { engine.OnTimer(); PressButtonsControl(); } //--- If the last trading event changed if(engine.LastTradeEvent()!=last_trade_event) { last_trade_event=engine.LastTradeEvent(); Comment("\nLast trade event: ",engine.GetLastTradeEventDescription()); engine.ResetLastTradeEvent(); } //--- If there is an account event if(engine.IsAccountsEvent()) { //--- the last account event last_account_event=engine.LastAccountEvent(); //--- If this is a tester if(MQLInfoInteger(MQL_TESTER)) { //--- Get the list of all account events occurred simultaneously CArrayObj* list=engine.GetListAccountEvents(); if(list!=NULL) { //--- Get the next event in a loop int total=list.Total(); for(int i=0;i<total;i++) { //--- take an event from the list CEventBaseObj *event=list.At(i); if(event==NULL) continue; //--- Send an event to the event handler long lparam=event.LParam(); double dparam=event.DParam(); string sparam=event.SParam(); OnDoEasyEvent(CHARTEVENT_CUSTOM+event.ID(),lparam,dparam,sparam); } } } } //--- If there is a symbol collection event if(engine.IsSymbolsEvent()) { //--- the last event in the symbol collection last_symbol_event=engine.LastSymbolsEvent(); //--- If this is a tester if(MQLInfoInteger(MQL_TESTER)) { //--- Get the list of all symbol events occurred simultaneously CArrayObj* list=engine.GetListSymbolsEvents(); if(list!=NULL) { //--- Get the next event in a loop int total=list.Total(); for(int i=0;i<total;i++) { //--- take an event from the list CEventBaseObj *event=list.At(i); if(event==NULL) continue; //--- Send an event to the event handler long lparam=event.LParam(); double dparam=event.DParam(); string sparam=event.SParam(); OnDoEasyEvent(CHARTEVENT_CUSTOM+event.ID(),lparam,dparam,sparam); } } } } //--- If the trailing flag is set if(trailing_on) { TrailingPositions(); TrailingOrders(); } } //+------------------------------------------------------------------+
Aquí todo es simple: todos los cambios necesarios en cuanto al procesamiento de los eventos de cuenta y los eventos de la colección de símbolos han sido comentados en el listado.
Como podemos observar, ahora el procesamiento de eventos es absolutamente idéntico para cualquier objeto, ya sea de una cuenta, o de una colección de símbolos: todo se reduce a obtener la lista de eventos y enviar cada evento sucesivo de la lista al manejador OnDoEasyEvent() del asesor que procesa los eventos de la biblioteca. Esto es posible gracias a los cambios realizados en la herencia de los objetos de la biblioteca del objeto básico CBaseObj, en el que se ha implementado el procesamiento de los eventos de los objetos herederos.
Añadimos al manejador del asesor OnDoEasyEvent() el código de procesamiento de los eventos de la colección de símbolos:
//+------------------------------------------------------------------+ //| Handling DoEasy library events | //+------------------------------------------------------------------+ void OnDoEasyEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { int idx=id-CHARTEVENT_CUSTOM; string event="::"+string(idx); int digits=Digits(); //--- Handling trading events if(idx>TRADE_EVENT_NO_EVENT && idx<TRADE_EVENTS_NEXT_CODE) { event=EnumToString((ENUM_TRADE_EVENT)ushort(idx)); digits=(int)SymbolInfoInteger(sparam,SYMBOL_DIGITS); } //--- Handling account events else if(idx>ACCOUNT_EVENT_NO_EVENT && idx<ACCOUNT_EVENTS_NEXT_CODE) { Print(TimeMSCtoString(lparam)," ",sparam,": ",engine.GetAccountEventDescription((ENUM_ACCOUNT_EVENT)idx)); //--- if this is an equity increase if((ENUM_ACCOUNT_EVENT)idx==ACCOUNT_EVENT_EQUITY_INC) { //--- Close a position with the highest profit exceeding zero when the equity exceeds the value, //--- specified in the CAccountsCollection::InitControlsParams() method for //--- the m_control_equity_inc variable tracking the equity growth by 15 units (by default) //--- AccountCollection file, InitControlsParams() method, string 1199 //--- Get the list of all open positions CArrayObj* list_positions=engine.GetListMarketPosition(); //--- Select positions with the profit exceeding zero list_positions=CSelect::ByOrderProperty(list_positions,ORDER_PROP_PROFIT_FULL,0,MORE); if(list_positions!=NULL) { //--- Sort the list by profit considering commission and swap list_positions.Sort(SORT_BY_ORDER_PROFIT_FULL); //--- Get the position index with the highest profit int index=CSelect::FindOrderMax(list_positions,ORDER_PROP_PROFIT_FULL); if(index>WRONG_VALUE) { COrder* position=list_positions.At(index); if(position!=NULL) { //--- Get a ticket of a position with the highest profit and close the position by a ticket #ifdef __MQL5__ trade.PositionClose(position.Ticket()); #else PositionClose(position.Ticket(),position.Volume()); #endif } } } } } //--- Handling symbol events else if(idx>SYMBOL_EVENT_NO_EVENT && idx<SYMBOL_EVENTS_NEXT_CODE) { string name=""; //--- Market Watch window event if(idx<SYMBOL_EVENT_TRADE_DISABLE) { string descr=engine.GetMWEventDescription((ENUM_SYMBOL_EVENT)idx); name=(idx==SYMBOL_EVENT_MW_SORT ? "" : ": "+sparam); Print(TimeMSCtoString(lparam)," ",descr,name); } //--- Symbol event else { CSymbol *symbol=engine.GetSymbolObjByName(sparam); if(symbol!=NULL) { string descr=": "+symbol.EventDescription((ENUM_SYMBOL_EVENT)ushort(idx)); Print(TimeMSCtoString(lparam)," ",sparam,descr); } } } } //+------------------------------------------------------------------+
Aquí solo hay dos opciones: el procesamiento de los eventos de la ventana "Observación de mercado" y el procesamiento de los eventos de los símbolos de la colección.
Para los eventos de la ventana de observación de mercado
creamos el mensaje necesario y lo mostramos en el diario,
y para los eventos de los símbolos
obtenemos de la lista el símbolo según el nombre del parámetro de línea de evento sparam, obtenemos del objeto de símbolo la descripción de línea de su evento, lo añadimos al texto creado y mostramos el texto en el diario.
No vamos a realizar ninguna acción adicional para las simulaciones.
Aquí se terminan los cambios para el asesor de prueba.
Podrá ver el listado completo del asesor en los archivos adjuntos al artículo.
Si iniciamos el asesor en una cuenta demo, pasado cierto tiempo, podremos ver en el diario varias entradas sobre los cambios en las propiedades de los símbolos. Por ejemplo, al iniciar el asesor en la víspera de la apertura de una sesión comercial el lunes, en el diario se comenzarán a mostrar de forma activa entradas sobre el cambio en el spread de diferentes símbolos.
Como ejemplo, para solo cuatro símbolos en la ventana de "Observación de mercado" se han mostrado durante la última hora multitud de mensajes sobre el cambio en el spread de los símbolos:
2019.07.15 04:02:24.167 TestDoEasyPart16 (EURUSD,H4) Working with symbols from the "Market Watch" window. The number of symbols used: 4 2019.07.15 04:02:25.762 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:02:27.316 GBPUSD: Spread value in points decreased by -7 (351) 2019.07.15 04:02:31.259 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:02:32.676 USDCHF: Spread value in points increased by 4 (287) 2019.07.15 04:02:33.761 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:02:35.218 USDCHF: Spread value in points decreased by -4 (283) 2019.07.15 04:02:46.261 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:02:47.680 USDCHF: Spread value in points increased by 4 (287) 2019.07.15 04:02:48.761 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:02:50.222 USDCHF: Spread value in points decreased by -4 (283) 2019.07.15 04:02:53.760 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:02:55.305 USDCHF: Spread value in points increased by 4 (287) 2019.07.15 04:02:56.760 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:02:58.221 USDCHF: Spread value in points decreased by -4 (283) 2019.07.15 04:03:01.261 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:02.683 USDCHF: Spread value in points increased by 4 (287) 2019.07.15 04:03:03.760 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:05.226 USDCHF: Spread value in points decreased by -4 (283) 2019.07.15 04:03:16.260 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:17.673 USDCHF: Spread value in points increased by 4 (287) 2019.07.15 04:03:18.789 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:20.219 USDCHF: Spread value in points decreased by -4 (283) 2019.07.15 04:03:30.832 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:32.686 USDCHF: Spread value in points increased by 4 (287) 2019.07.15 04:03:33.819 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:35.219 USDCHF: Spread value in points decreased by -4 (283) 2019.07.15 04:03:38.820 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:39.926 USDCHF: Spread value in points increased by 4 (287) 2019.07.15 04:03:41.821 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:43.221 USDCHF: Spread value in points decreased by -4 (283) 2019.07.15 04:03:45.820 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:47.673 USDCHF: Spread value in points increased by 4 (287) 2019.07.15 04:03:48.836 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:50.234 USDCHF: Spread value in points decreased by -4 (283) 2019.07.15 04:03:50.865 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:03:52.598 USDCHF: Spread value in points increased by 51 (334) 2019.07.15 04:03:58.867 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:04:00.450 EURUSD: Spread value in points decreased by -42 (50) 2019.07.15 04:03:58.868 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:04:00.430 USDCHF: Spread value in points decreased by -96 (238) 2019.07.15 04:03:59.417 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:04:00.934 USDCHF: Spread value in points increased by 22 (260) 2019.07.15 04:03:59.912 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:04:01.431 USDCHF: Spread value in points decreased by -5 (255) 2019.07.15 04:04:35.445 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:04:36.984 GBPUSD: Spread value in points decreased by -112 (239) 2019.07.15 04:04:35.445 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:04:36.985 EURUSD: Spread value in points decreased by -7 (43) 2019.07.15 04:04:35.445 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:04:36.984 USDCHF: Spread value in points decreased by -127 (128) 2019.07.15 04:04:58.460 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:05:00.102 GBPUSD: Spread value in points decreased by -207 (32) 2019.07.15 04:04:58.959 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:05:00.696 EURUSD: Spread value in points decreased by -4 (39) 2019.07.15 04:05:01.006 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:05:02.697 EURUSD: Spread value in points increased by 3 (42) 2019.07.15 04:05:02.037 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:05:03.686 EURUSD: Spread value in points decreased by -32 (10)
... hemos omitido muchas líneas ...
2019.07.15 04:55:09.780 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:11.578 GBPUSD: Spread value in points decreased by -3 (29) 2019.07.15 04:55:09.780 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:11.478 USDCHF: Spread value in points increased by 4 (32) 2019.07.15 04:55:10.482 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:11.681 USDCHF: Spread value in points decreased by -3 (29) 2019.07.15 04:55:11.623 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:13.477 USDCHF: Spread value in points increased by 3 (32) 2019.07.15 04:55:12.111 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:13.884 USDCHF: Spread value in points decreased by -5 (27) 2019.07.15 04:55:13.626 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:15.275 USDCHF: Spread value in points increased by 4 (31) 2019.07.15 04:55:19.628 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:21.381 USDCHF: Spread value in points decreased by -3 (28) 2019.07.15 04:55:20.126 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:21.882 USDCHF: Spread value in points increased by 3 (31) 2019.07.15 04:55:28.659 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:30.292 EURUSD: Spread value in points increased by 3 (20) 2019.07.15 04:55:33.690 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:35.298 EURUSD: Spread value in points decreased by -3 (17) 2019.07.15 04:55:53.298 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:55.137 EURUSD: Spread value in points increased by 3 (20) 2019.07.15 04:55:53.826 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:55.643 EURUSD: Spread value in points decreased by -3 (17) 2019.07.15 04:55:54.906 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:56.632 USDCHF: Spread value in points decreased by -3 (28) 2019.07.15 04:55:55.912 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:57.536 USDCHF: Spread value in points increased by 4 (32) 2019.07.15 04:55:56.907 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:58.636 USDCHF: Spread value in points decreased by -4 (28) 2019.07.15 04:55:57.434 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:55:58.832 USDCHF: Spread value in points increased by 4 (32) 2019.07.15 04:55:59.949 TestDoEasyPart16 (EURUSD,H4) 2019.07.15 00:56:01.538 USDCHF: Spread value in points decreased by -3 (29)
Vamos a iniciar el asesor con dos símbolos en el simulador, así veremos qué entradas nos muestra.
En los ajustes del simulador, para el parámetro de entrada del asesor Mode of used symbols list, seleccionamos de la lista desplegable "Trabajar con la lista de símbolos establecida", y en el parámetro List of used symbols (comma - separator) introducimos los dos símbolos separados por una coma: EURUSD,GBPUSD e iniciamos el test visual del asesor:
En el diario se muestran entradas sobre los eventos de ambos símbolos, concretamente, sobre los cambios en los spreads de los símbolos usados. Cuando las propiedades de la cuenta cambian (aquí aumenta el beneficio actual), en el diario se muestran entradas sobre ello, cerrándose asimismo las posiciones rentables.
¿Qué es lo próximo?
En el siguiente artículo, implementaremos un cómodo acceso desde el programa al cambio de valores de las propiedades controladas y monitoreadas de los objetos, basado en la clase del objeto básico CBaseObj.
Más abajo se adjuntan todos los archivos de la versión actual de la biblioteca y los archivos del asesor de prueba. Puede descargarlo todo y ponerlo a prueba por sí mismo.
Si tiene preguntas, observaciones o sugerencias, podrá concretarlas en los comentarios al artículo.
Artículos de esta serie:
Parte 1: Concepto y organización de datosParte 2: Colecciones de las órdenes y transacciones históricas
Parte 3: Colección de órdenes y posiciones de mercado, organización de la búsqueda
Parte 4: Eventos comerciales. Concepto
Parte 5: Clases y colección de eventos comerciales. Envío de eventos al programa.
Parte 6. Eventos en la cuenta con compensación
Parte 7. Eventos de activación de órdenes StopLimit, preparación de la funcionalidad para el registro de los eventos de modificación de órdenes y posiciones
Parte 8. Eventos de modificación de órdenes y posiciones
Parte 9. Compatibilidad con MQL4 - Preparando los datos
Parte 10. Compatibilidad con MQL4 - Eventos de apertura de posición y activación de órdenes pendientes
Parte 11. Compatibilidad con MQL4 - Eventos de cierre de posiciones
Parte 12. Implementando la clase de objeto "cuenta" y la colección de objetos de cuenta
Parte 13. Eventos del objeto "cuenta"
Parte 14. El objeto "Símbolo"
Parte 15. Colección de objetos de símbolo
Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/7071
![Desarrollando el Oscilador de Promedio de Pivote (PMO): un nuevo indicador para la Media Móvil Acumulativa](https://c.mql5.com/2/37/PMO_200x200.png)
![Constructor de estrategias basado en las figuras técnicas de Merrill](https://c.mql5.com/2/37/Article_Logo.png)
![Biblioteca para el desarrollo rápido y sencillo de programas para MetaTrader (Parte XVII): Interactividad de los objetos de la biblioteca.](https://c.mql5.com/2/36/MQL5-avatar-doeasy__12.png)
![Creando un EA gradador multiplataforma (última parte): la diversificación como método para aumentar la rentabilidad](https://c.mql5.com/2/37/mql5_ea_adviser_grid.png)
![MQL5 - Lenguaje de estrategias comerciales para el terminal de cliente MetaTrader 5](https://c.mql5.com/i/registerlandings/logo-2.png)
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso