Discusión sobre el artículo "Biblioteca para el desarrollo rápido y sencillo de programas para MetaTrader (Parte XI) Compatibilidad con MQL4 - Eventos de cierre de posición"
Tengo algunas observaciones relacionadas con el efecto de las variables de tiempo en milisegundos, y en particular sobre lafunción CHistoryCollection::GetListByTime(...) con respecto a la versión MQL5.
Son ( en orden decreciente de relevancia):
1) Tanto las variables datetime como las variables long millisecond time representan el tiempo transcurrido desde el 01/01/1970. Sin embargo, existe un factor de 1000 entre los valores efectivamente almacenados. Por lo tanto, ambos tipos no pueden asignarse directamente entre sí. Como consecuencia GetListByTime(..) dejó de funcionar tras el cambio, ya que almacena directamente los parámetros datetime en la propiedad time millisecond de COrder m_order_instance. Una posible solución podría ser incluir dos nuevas funciones de conversión (probablemente en delib.mqh) para encargarse de ese factor 1000:
//+------------------------------------------------------------------+ //| Convierte el tiempo en milisegundos a datetime | //+------------------------------------------------------------------+ datetime TimeMSCtoDate(const long time_msc) { return datetime(time_msc/1000); } //+------------------------------------------------------------------+ //| Convierte datetime a tiempo en milisegundos || //+------------------------------------------------------------------+ long DatetoTimeMSC(const datetime time_sec) { return long(time_sec * 1000); }
Este tipo de problema no se produciría si MetaQuotes hubiera definido desde el principio variables datetime para que el tiempo transcurrido fuera en milisegundos, o incluso en microsegundos (¿quién dice que dentro de diez años los robots no operarán en menos de milisegundos?).
De todas formas, el problema también está presente al menos en las funciones GetListByTime(...) de las clases CEventsCollection y CMarketCollection, quizás en algunos otros lugares...
2) La colección History es un objeto que sabe si está ordenado o no, y si lo está, cuál es la propiedad de ordenación (funciónSortMode() ), mientras que la función GetListByTime(...) asume que la colección ya está ordenada por las propiedades ORDER_PROP_TIME_OPEN u ORDER_PROP_TIME_CLOSE (sólo ORDER_PROP_TIME_OPEN en las versiones CEventsCollection y CMarketCollection ). Siguiendo la filosofía de la programación orientada a objetos, GetListByTime(...) debería comprobar si la colección está ordenada correctamente antes de continuar.
De hecho, el programa de ejemplo TestDoEasyPart03_1.mq5 creó una colección de históricos ordenada por ORDER_PROP_TIME_OPEN (el valor por defecto en MT5) y luego llamó a GetListByTime(...,SELECT_BY_TIME_CLOSE). Con esa comprobación, ¡esto habría aparecido!
3) No es gran cosa, pero ya que se supone que MT5 es el nuevo estándar, ¿por qué no dejar que SELECT_BY_TIME_OPEN sea el valor por defecto del parámetro select_time_mode de la función CHistoryCollection::GetListByTime(...)?
Siguiendo las sugerencias anteriores, este sería el código de la función CHistoryCollection::GetListByTime(...):
public: ....... //--- Seleccionar pedidos de la colección con tiempo desde hora_inicial hasta hora_final CArrayObj *GetListByTime(const datetime begin_time=0,const datetime end_time=0, const ENUM_SELECT_BY_TIME select_time_mode=SELECT_BY_TIME_OPEN); ....... //+------------------------------------------------------------------+ //| Seleccionar pedidos de la colección con tiempo | //| de hora_inicio a hora_fin| //+------------------------------------------------------------------+ CArrayObj *CHistoryCollection::GetListByTime(const datetime begin_time=0,const datetime end_time=0, const ENUM_SELECT_BY_TIME select_time_mode=SELECT_BY_TIME_OPEN) { ENUM_ORDER_PROP_INTEGER property=(select_time_mode==SELECT_BY_TIME_CLOSE ? ORDER_PROP_TIME_CLOSE : ORDER_PROP_TIME_OPEN); if(property != (ENUM_ORDER_PROP_INTEGER)m_list_all_orders.SortMode()) { ::Print(DFUN+"History list not prpperly sorted"); //Tal vez mensaje para añadir a ENUM_MESSAGES_LIB return NULL; } CArrayObj *list=new CArrayObj(); if(list==NULL) { ::Print(DFUN+CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_TEMP_LIST)); return NULL; } datetime begin=begin_time,end=(end_time==0 ? END_TIME : end_time); if(begin_time>end_time) begin=0; list.FreeMode(false); ListStorage.Add(list); //--- this.m_order_instance.SetProperty(property,DatetoTimeMSC(begin)); int index_begin=this.m_list_all_orders.SearchGreatOrEqual(&m_order_instance); if(index_begin==WRONG_VALUE) return list; this.m_order_instance.SetProperty(property,DatetoTimeMSC(end)); int index_end=this.m_list_all_orders.SearchLessOrEqual(&m_order_instance); if(index_end==WRONG_VALUE) return list; for(int i=index_begin; i<=index_end; i++) list.Add(this.m_list_all_orders.At(i)); return list; }
Tengo algunas observaciones relacionadas con el efecto de las variables de tiempo en milisegundos, y en particular sobre la función CHistoryCollection::GetListByTime(...) con respecto a la versión MQL5.
Son ( en orden decreciente de relevancia):
1) Tanto las variables datetime como las variables long millisecond time representan el tiempo transcurrido desde el 01/01/1970. Sin embargo, existe un factor de 1000 entre los valores efectivamente almacenados. Por lo tanto, ambos tipos no pueden asignarse directamente entre sí. Como consecuencia GetListByTime(..) dejó de funcionar tras el cambio, ya que almacena directamente los parámetros datetime en la propiedad time millisecond de COrder m_order_instance. Una posible solución podría ser incluir dos nuevas funciones de conversión (probablemente en delib.mqh ) para encargarse de ese factor 1000:
Este tipo de problema no se produciría si MetaQuotes hubiera definido desde el principio variables datetime para que el tiempo transcurrido fuera en milisegundos, o incluso en microsegundos (¿quién dice que dentro de diez años los robots no operarán en menos de milisegundos?).
De todas formas, el problema también está presente al menos en las funciones GetListByTime(...) de las clases CEventsCollection y CMarketCollection, quizás en algunos otros lugares...
2) La colección History es un objeto que sabe si está ordenado o no, y si lo está, cuál es la propiedad de ordenación (. SortMode() ), mientras que la función GetListByTime(...) asume que la colección ya está ordenada por las propiedades ORDER_PROP_TIME_OPEN u ORDER_PROP_TIME_CLOSE (sólo ORDER_PROP_TIME_OPEN en las versiones CEventsCollection y CMarketCollection ). Siguiendo la filosofía de la programación orientada a objetos, GetListByTime(...) debería comprobar si la colección está correctamente ordenada antes de continuar.
De hecho, el programa de ejemplo TestDoEasyPart03_1.mq5 creó una colección de históricos ordenada por ORDER_PROP_TIME_OPEN (el valor por defecto en MT5) y luego llamó a GetListByTime(...,SELECT_BY_TIME_CLOSE). Con esa comprobación, ¡habría aparecido esto!
3) No es gran cosa, pero ya que se supone que MT5 es el nuevo estándar, ¿por qué no dejar que SELECT_BY_TIME_OPEN sea el valor por defecto del parámetro select_time_mode de la función CHistoryCollection::GetListByTime(...)?
Siguiendo las sugerencias anteriores, este sería el código de la función CHistoryCollection::GetListByTime(...):
Gracias. En las versiones posteriores de la biblioteca (en los artículos por encima de XI), parece que la conversión de tiempo ya se utiliza (por lo general dejé datetime - todo está en largo).
Yo no entendía un poco acerca de las colecciones - por favor, mostrar un ejemplo de clasificación incorrecta. Deseable en el artículo más reciente disponible (ya que los artículos describen la secuencia de creación de una biblioteca, y todo cambia)
- 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
Artículo publicado Biblioteca para el desarrollo rápido y sencillo de programas para MetaTrader (Parte XI) Compatibilidad con MQL4 - Eventos de cierre de posición:
Continuamos creando la gran biblioteca multiplataforma cuyo objetivo es simplificar la escritura de programas para las plataformas MetaTrader 5 y MetaTrader 4. En la décima parte, continuamos trabajando con la compatibilidad de la biblioteca con MQL4 e implementamos la definición de los eventos de apertura de posición y activación de órdenes pendientes. En el presente artículo, vamos a implementar la defición de los eventos de cierre de posición, eliminando al mismo tiempo las propiedades innecesarias de las órdenes.
Ahora, los eventos de cierre parcial y de eliminación de una orden pendiente no se determinan como el mismo evento de cierre de posición, sino que se diferencian.
Iniciamos de nuevo y pulsamos los botones, prestando atención a la determinación de eventos:
Podemos ver que se determinan correctamente. El evento de cierre con posición opuesta se determina correctamente; asimismo, la modificación de los niveles stop de las posiciones y los precios de las órdenes pendientes funcionan y se monitorean de la forma habitual.
Autor: Artyom Trishkin