Discusión sobre el artículo "Biblioteca para el desarrollo rápido y sencillo de programas para MetaTrader (Parte X): Compatibilidad con MQL4" - página 3

 
Alexey Viktorov:

Artem, por favor, dime qué papel desempeña la sección de código resaltada.

¿Cómo puede ejecutarse este código si el temporizador no está activado?

Pero si se elimina esta sección de código, los mensajes de eventos no se imprimen. Pero todo funciona con ella.

Y me gustaría poder obtener un ticket, precios y quizás algunas otras propiedades de posiciones y órdenes junto con el mensaje de evento.

Creo que has cambiado el comentario. En OnTimer() se comprueba el EA no en el tester:

/************************Expert tick function************************/
void OnTick()
{
//--- Inicialización del último evento comercial
   static ENUM_TRADE_EVENT last_event=WRONG_VALUE;
//--- Si trabaja en el probador
   if(MQLInfoInteger(MQL_TESTER))
     {
      engine.OnTimer();
     }
//--- Si el último evento comercial ha cambiado
   if(engine.LastTradeEvent()!=last_event)
     {
      last_event=engine.LastTradeEvent();
      Comment("last_event: ",EnumToString(last_event));
      Print(__FUNCTION__, " last_event: ",EnumToString(last_event));
      //engine.ResetLastTradeEvent();
      //Print("último_evento: ",EnumToString(último_evento));
     }

}
/***************************Timer function***************************/
void OnTimer()
{
//--- Inicialización del último evento comercial
   static ENUM_TRADE_EVENT last_event=WRONG_VALUE;
//--- Si el trabajo no es  в тестере
   if(!MQLInfoInteger(MQL_TESTER))
     {
      engine.OnTimer();
     }
}
/*******************************************************************/

Y compara dos manejadores: en OnTick( ) el temporizador de la libreria se inicia solo en el tester, y en OnTimer() el temporizador de la libreria se inicia solo no en el t ester - porque en MQL4 el temporizador no funciona en el tester, y nosotros trabajamos en ticks en el tester.

Ahora haré un ejemplo.

 
Artyom Trishkin:

Creo que has cambiado el comentario.

El comentario cambió solo, yo no lo toqué.))))))

Sólo copié en un lugar y pegué en diferentes lugares y no presté atención. Pero luego puse una negación en forma de ! y no importante no lo toqué.

Pero la pregunta sigue sin respuesta: Si el temporizador no se inicia en OnInit(), ¿cuál es el punto del controlador OnTimer() y por qué el código en él se ejecuta al menos una vez.

Básicamente, he conseguido los mensajes al log. Falta obtener las propiedades de los items. Tipo, ticket, precios y hora de apertura, cierre, modificación.

 
Alexey Viktorov:

Y me gustaría poder obtener ticket, precios y quizás algunas otras propiedades de posiciones y órdenes junto con el mensaje del evento.

No en el probador se puede obtener el ticket de la orden del último evento en OnChartEvent() - parámetro lparam. En dparam se almacena el precio. En sparam - símbolo.

Para obtener datos en el probador, actualmente se debe utilizar el código de evento que se obtiene con engine.LastTradeEvent() - porque todo depende del evento - si se trata de una modificación, es necesario obtener una lista de modificaciones, y si se trata de un cambio en el número de órdenes, es necesario obtener listas de estas nuevas órdenes.

Necesitamos añadir en CEngine para devolver los valores necesarios al programa. Todavía no he llegado al punto de enviar información al programa - todavía estoy describiendo la preparación de los datos necesarios. En futuros artículos llegaremos a la clase que da fácil acceso a todos los datos necesarios. Y ahora - si lo necesita con urgencia, es necesario añadir a CEngine el retorno de la lista de la clase-colección de eventos - la propia clase tiene la recepción de esta lista, aquí están - todas las listas en la sección pública CEventCollection:

public:
//--- Selecciona eventos de la colección con tiempos comprendidos entre begin_time y end_time
   CArrayObj        *GetListByTime(const datetime begin_time=0,const datetime end_time=0);
//--- Devuelve la lista-colección completa de eventos "tal cual"
   CArrayObj        *GetList(void)                                                                       { return &this.m_list_events;                                           }
//--- Devuelve una lista por la propiedad seleccionada (1) entero, (2) real y (3) cadena que satisface el criterio comparado
   CArrayObj        *GetList(ENUM_EVENT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL)  { return CSelect::ByEventProperty(this.GetList(),property,value,mode);  }
   CArrayObj        *GetList(ENUM_EVENT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByEventProperty(this.GetList(),property,value,mode);  }
   CArrayObj        *GetList(ENUM_EVENT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByEventProperty(this.GetList(),property,value,mode);  }

Todos los eventos se almacenan en la lista m_list_events, y estos métodos devuelven la lista completa o filtrada por un criterio dado.

Para obtener el último evento basta con crear en CEngine la devolución de esta lista al programa, y en el programa tomar el evento requerido de la lista.

Todo esto se automatizará pronto - todavía no está en la cola.

Si todavía necesita hacer una muleta, su discusión - en un privado. No vale la pena aquí - no se aplica a la biblioteca, ya que está en desarrollo, y más trabajo normal y adecuado se llevará a cabo para obtener todos y cualquier evento requerido en el programa.

 
Alexey Viktorov:

El comentario ha cambiado solo, no lo he tocado.)))))

Simplemente copié en un sitio y pegué en otros diferentes y no presté atención. Pero luego puse una negación en forma de ! y no toqué lo importante.

Pero la pregunta sigue sin respuesta: Si el temporizador no se inicia en OnInit(), qué sentido tiene el manejador OnTimer() y por qué se ejecuta el código en él al menos una vez.

Básicamente, he conseguido los mensajes al log. Falta obtener las propiedades de los items. Tipo, ticket, precios y hora de apertura, cierre, modificación.

Explique lo que quieres decir? ¿Te refieres a la creación de un temporizador? Se crea en el constructor CEngine:

//+------------------------------------------------------------------+
//| Constructor CEngine|
//+------------------------------------------------------------------+
CEngine::CEngine() : m_first_start(true),m_last_trade_event(TRADE_EVENT_NO_EVENT)
  {
   this.m_list_counters.Sort();
   this.m_list_counters.Clear();
   this.CreateCounter(COLLECTION_COUNTER_ID,COLLECTION_COUNTER_STEP,COLLECTION_PAUSE);
   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);
   ::ResetLastError();
   #ifdef __MQL5__
      if(!::EventSetMillisecondTimer(TIMER_FREQUENCY))
         ::Print(DFUN,"Fallo al crear temporizador. Error: ","Could not create timer. Error: ",(string)::GetLastError());
   //---__MQL4__
   #else 
      if(!this.IsTester() && !::EventSetMillisecondTimer(TIMER_FREQUENCY))
         ::Print(DFUN,"Fallo al crear temporizador. Error: ","Could not create timer. Error: ",(string)::GetLastError());
   #endif 
  }
//+------------------------------------------------------------------+
 
Artyom Trishkin:

No en el probador se puede obtener el ticket de pedido del último evento en OnChartEvent() - parámetro lparam. En dparam se almacena el precio. En sparam - símbolo.

Ya lo he encontrado, gracias. Y mediante la obtención de una entrada se puede obtener todo lo que necesita. Excepto de qué precio hubo una modificación. O hacer una muleta real para saber el precio antes de la modificación. En principio no es muy necesario todavía.

 
Alexey Viktorov:

Básicamente tengo los mensajes de registro. Sólo necesito obtener las propiedades de las posiciones. Tipo, ticket, precios y hora de apertura, cierre, modificación.

Sin embargo, para una solución rápida, añadir un retorno de lista de eventos a la sección pública de CEngine:

public:
   //--- Devuelve una lista de (1) posiciones de mercado, (2) órdenes pendientes y (3) órdenes de mercado
   CArrayObj*           GetListMarketPosition(void);
   CArrayObj*           GetListMarketPendings(void);
   CArrayObj*           GetListMarketOrders(void);
   //--- Devuelve la lista de (1) órdenes históricas, (2) órdenes pendientes eliminadas, (3) operaciones, (4) todas las órdenes de mercado de una posición por su identificador
   CArrayObj*           GetListHistoryOrders(void);
   CArrayObj*           GetListHistoryPendings(void);
   CArrayObj*           GetListDeals(void);
   CArrayObj*           GetListAllOrdersByPosID(const ulong position_id);
//--- Devuelve una lista de eventos
   CArrayObj*           GetListAllEvents(void)                          { return this.m_events.GetList();      }
//--- Reinicia el último evento comercial
   void                 ResetLastTradeEvent(void)                       { this.m_events.ResetLastTradeEvent(); }
//--- Devuelve (1) último evento de operación, (2) indicador de cuenta de cobertura, (3) indicador de operación de comprobación
   ENUM_TRADE_EVENT     LastTradeEvent(void)                      const { return this.m_last_trade_event;      }
   bool                 IsHedge(void)                             const { return this.m_is_hedge;              }
   bool                 IsTester(void)                            const { return this.m_is_tester;             }
//--- Crea un contador de tiempo
   void                 CreateCounter(const int id,const ulong frequency,const ulong pause);
//--- Temporizador
   void                 OnTimer(void);
//--- Constructor/Destructor
                        CEngine();
                       ~CEngine();
  };
//+------------------------------------------------------------------+

En el EA, añadir este código:

//+------------------------------------------------------------------+
//| Función tick experto|
//+------------------------------------------------------------------+
void OnTick()
  {
//--- Inicialización del último evento comercial
   static ENUM_TRADE_EVENT last_event=WRONG_VALUE;
//--- Si trabaja en el probador
   if(MQLInfoInteger(MQL_TESTER))
     {
      engine.OnTimer();
      PressButtonsControl();
     }
//--- Si el último evento comercial ha cambiado
   if(engine.LastTradeEvent()!=last_event)
     {
      last_event=engine.LastTradeEvent();
      Comment("\nlast_event: ",EnumToString(last_event));
      CArrayObj* list=engine.GetListAllEvents();
      if(list!=NULL)
        {
         if(list.Total()>0)
           {
            CEvent* event=list.At(list.Total()-1);
            if(event!=NULL)
              {
               event.Print();
              }
           }
        }
     }
//--- Si el indicador de finalización está activado
   if(trailing_on)
     {
      TrailingPositions();
      TrailingOrders();
     }
  }
//+------------------------------------------------------------------+

Y el último evento se imprimirá en el registro

 
Artyom Trishkin:

¿A qué se refiere? ¿Te refieres a la creación de un temporizador? Se crea en el constructor CEngine:

Bueno, tuviste que ir a través de toda la biblioteca para eso. )))

 
Alexey Viktorov:

Ya lo he encontrado, gracias. Y si usted consigue un boleto, usted puede conseguir todo lo que necesita. Excepto a qué precio se hizo la modificación. O hacer una muleta real para saber el precio antes de la modificación. Realmente no lo necesito todavía.

Ya te he dado el código - allí está todo, y el precio antes de la modificación también.

 
Alexey Viktorov:

Bueno, para eso has tenido que buscar en toda la biblioteca. )))

No. Basta con leer los artículos

 

Y esto es lo que ocurrió:

Mientras ejecutaba este código en la demo, se estableció una orden limitada y se eliminó

443342388 2019.05.27 14:54:10 buy limit 0.01 eurusd 1.11835 0.00000 0.00000 2019.05.27 15:01:14 1.11972 cancelled 

Y de repente, durante el siguiente mocking, una posición fue modificada, una posición fue abierta y una posición fue cerrada. ¿Pero de dónde salió el registro de borrar una orden borrada hace tiempo?

2019.05.27 18:34:11.903 00 EURUSD,H1: OnChartEvent: id=1002, event=TRADE_EVENT_PENDING_ORDER_REMOVED, lparam=443342388, dparam=1.11835, sparam=EURUSD
2019.05.27 18:34:11.903 00 EURUSD,H1: OnChartEvent: id=1024, event=TRADE_EVENT_POSITION_CLOSED, lparam=443417294, dparam=1.11933, sparam=EURUSD
2019.05.27 18:34:11.903 00 EURUSD,H1: - Отложенный ордер удалён: 2019.05.27 14:54:10.000 -
EURUSD Удалён 0.01 Buy Limit #443342388  по цене 1.11835
2019.05.27 18:34:11.903 00 EURUSD,H1: - Позиция закрыта: 2019.05.27 18:33:02.000 -
EURUSD Закрыт Sell #443417294  по цене 1.11912, профит -0.21 USD
2019.05.27 18:33:02.755 00 EURUSD,H1: OnChartEvent: id=1022, event=TRADE_EVENT_POSITION_OPENED, lparam=443417294, dparam=1.11912, sparam=EURUSD
2019.05.27 18:33:02.755 00 EURUSD,H1: - Позиция открыта: 2019.05.27 18:33:02.000 -
EURUSD Открыт 0.01 Sell #443417294 [0.01 Market order Sell #443417294]  по цене 1.11912
2019.05.27 18:29:21.913 00 EURUSD,H1: OnChartEvent: id=1050, event=TRADE_EVENT_MODIFY_POSITION_TAKE_PROFIT, lparam=443218277, dparam=1.12218, sparam=EURUSD
2019.05.27 18:29:21.913 00 EURUSD,H1: - Модифицирован TakeProfit позиции: 2019.05.27 18:27:45.000 -
EURUSD Buy #443218277:  модифицирован TakeProfit: [1.12240 --> 1.12218]