English Русский 中文 Deutsch 日本語 Português
preview
Operar con noticias de manera sencilla (Parte 6): Ejecución de operaciones (III)

Operar con noticias de manera sencilla (Parte 6): Ejecución de operaciones (III)

MetaTrader 5Sistemas comerciales |
355 2
Kabelo Frans Mampa
Kabelo Frans Mampa

Introducción

En este artículo realizaremos mejoras en la base de datos de almacenamiento, se añadirán nuevas vistas para presentar datos como la visualización de las fechas del último evento de noticias o del próximo evento de noticias para cada evento único en el Calendario económico MQL5, lo que mejorará la experiencia del usuario al utilizar el programa, ya que le permitirá conocer los eventos futuros o pasados. Además, se ampliará el menú de aportaciones de expertos para incluir métodos de filtrado de noticias y de introducción de órdenes de stop.

Además, el código experto se actualizará para utilizar el código anterior escrito con el fin de reducir el tiempo de ejecución del experto en el probador de estrategias del artículo «Operar con noticias de manera sencilla (Parte 4): Mejora del rendimiento», así como el código del artículo «Operar con noticias de manera sencilla (Parte 5): Ejecución de operaciones (II)», en el que gestionamos el deslizamiento y las órdenes stop abiertas.


Entradas de configuración de noticias

  • SELECT NEWS OPTION: El objetivo de esta opción es permitir diferentes perfiles de noticias. Los diferentes perfiles son:
    • NEWS SETTINGS: En este perfil de noticias, el usuario/comerciante puede filtrar los eventos de noticias según sus preferencias basándose en:
      1. CALENDAR IMPORTANCE (IMPORTANCIA DEL CALENDARIO)
      2. EVENT FREQUENCY (FRECUENCIA DEL EVENTO)
      3. EVENT SECTOR (SECTOR DE EVENTOS)
      4. EVENT TYPE (TIPO DE EVENTO)
      5. EVENT CURRENCY (DIVISA DEL EVENTO)
    • CUSTOM NEWS EVENTS: En este perfil de noticias, el usuario/comerciante puede filtrar los eventos de noticias a su gusto en función de los identificadores de evento introducidos como entrada, con un máximo de 14 identificadores de evento por entrada.

Opciones de entrada de configuración de noticias


Entradas de configuración de comercio

  • SELECT TRADE ENTRY OPTION: El objetivo de esta opción es permitir diferentes métodos de entrada en las operaciones. Estos métodos son, concretamente:
    • MARKET POSITION: En este método de entrada comercial, las transacciones solo se realizarán a través de la ejecución del mercado (operaciones de compra o venta). El requisito principal es que cualquier noticia que se elija para operar en esta selección de entradas comerciales debe tener un impacto que permita conocer de antemano la dirección de la operación (larga o corta, compra o venta).
    • STOP ORDERS: En este método de entrada en operaciones, las operaciones solo se ejecutarán con una orden Buy-Stop y Sell-Stop antes de que se produzca cualquier evento de noticias elegido. El requisito principal es que el usuario/comerciante establezca una desviación de precio para que el experto disponga de un margen de precio para colocar la orden Buy-Stop y Sell-Stop. Una vez que se active la orden Buy-Stop o Sell-Stop, se eliminará la orden opuesta. Por ejemplo, cuando se coloca una orden Buy-Stop y Sell-Stop antes de NFP (evento de noticias) y se activa la orden Buy-Stop, lo que significa que se ejecuta una posición de compra una vez que se alcanza un precio determinado, el experto eliminará activamente la orden Sell-Stop restante. Este método de entrada en el mercado no requiere que se produzca un impacto de eventos para realizar operaciones de antemano.
    • SINGLE STOP ORDER: En este método de entrada en operaciones, las operaciones solo se ejecutarán con una orden Buy-Stop o Sell-Stop. Los dos requisitos principales son:
      1. Cualquier noticia que se elija para operar en esta selección de entradas comerciales debe tener un impacto en el evento para conocer de antemano la dirección de la orden (Buy-Stop o Sell-Stop).
      2. El usuario/comerciante debe establecer una desviación de precio para que el experto disponga de un margen de precio para colocar la orden Buy-Stop o Sell-Stop.

Opciones de entrada de configuración comercial


Clase de noticias

En este archivo de encabezado llamado News.mqh declararemos una enumeración llamada NewsSelection fuera de la clase CNews. El objetivo de la enumeración es permitir a los usuarios/comerciantes seleccionar diferentes perfiles de noticias dentro de la entrada del experto. También tendremos una variable llamada myNewsSelection que almacenará la selección preferida del usuario/comerciante. Además, declararemos una estructura llamada CustomEvent. Esta estructura almacenará el valor booleano que decide si se filtran los identificadores de eventos en la matriz de cadenas EventIds dentro de la estructura. Además, la estructura tiene variables declaradas como CEvent1, que actuará como una de las cinco opciones que el usuario/comerciante puede utilizar para filtrar los identificadores de eventos personalizados.

Enumeraciones:

  • NewsSelection: Define dos perfiles:
    1. News_Select_Custom_Events: Para eventos de noticias personalizados.
    2. News_Select_Settings: Para la configuración de noticias.
    • myNewsSelection es una variable de este tipo enumerado que almacena la selección actual del perfil de noticias.

Estructuras:

  • CustomEvent: Una estructura para almacenar ID de eventos personalizados y un indicador (useEvents) que indica si estos eventos deben incluirse en la consulta.
    • There are five variables: CEvent1, CEvent2, CEvent3, CEvent4 y CEvent5 de tipo CustomEvent, cada uno de los cuales representa un grupo independiente de eventos.

//--- Enumeration for News Profiles
enum NewsSelection
  {
   News_Select_Custom_Events,//CUSTOM NEWS EVENTS
   News_Select_Settings//NEWS SETTINGS
  } myNewsSelection;

//--- Structure to store event ids and whether to use these ids
struct CustomEvent
  {
   bool              useEvents;
   string            EventIds[];
  } CEvent1,CEvent2,CEvent3,CEvent4,CEvent5;

Enumeración CalendarComponents:

  • CalendarComponents: Enumera varios componentes del calendario económico, como tablas y vistas utilizadas para estructurar datos relacionados con los horarios de verano (DST), información sobre eventos y datos sobre divisas.

Dentro de la enumeración CalendarComponents hemos añadido dos nuevos valores:

  1. RecentEventInfo_View
  2. UpcomingEventInfo_View

   //-- To keep track of what is in our database
   enum CalendarComponents
     {
      // ...
      RecentEventInfo_View,//View for Recent Dates For Events
      UpcomingEventInfo_View,//View for Upcoming Dates For Events
      // ...
     };

Función GetCalendar(CalendarData &Data[]):

  • Esta función recupera todos los datos relevantes del calendario de la base de datos del calendario almacenada y los guarda en la matriz Data.
  • Abre una base de datos (NEWS_DATABASE_FILE) y ejecuta una consulta SQL basada en la selección de noticias actual (myNewsSelection).
  • Dependiendo de si se selecciona News_Select_Custom_Events o News_Select_Settings, se genera una consulta SQL diferente para obtener la información del evento.
  • Eventos personalizados: une la tabla MQL5Calendar y la tabla TimeSchedule para recuperar eventos de noticias personalizados utilizando un filtro basado en identificadores de eventos personalizados.
  • Configuración de noticias: recupera datos de eventos filtrados según la configuración especificada por el usuario, como importancia, frecuencia, sector, tipo y divisa.
  • La función procesa los resultados de la consulta SQL y almacena los datos obtenidos en la matriz Data.
  • Si la consulta a la base de datos falla, muestra un error y la consulta SQL fallida.

   //--- Will Retrieve all relevant Calendar data for DB in Memory from DB in Storage
   void              GetCalendar(CalendarData &Data[])
     {
// ...
      string SqlRequest;

      //--- switch statement for different News Profiles
      switch(myNewsSelection)
        {
         case  News_Select_Custom_Events://CUSTOM NEWS EVENTS
            //--- Get filtered calendar DB data
            SqlRequest = StringFormat("Select MQ.EventId,MQ.Country,MQ.EventName,MQ.EventType,MQ.EventImportance,MQ.EventCurrency,"
                                      "MQ.EventCode,MQ.EventSector,MQ.EventForecast,MQ.EventPreValue,MQ.EventImpact,MQ.EventFrequency,"
                                      "TS.DST_UK,TS.DST_US,TS.DST_AU,TS.DST_NONE from %s MQ "
                                      "Inner Join %s TS on TS.ID=MQ.ID Where %s OR %s OR %s OR %s OR %s;",
                                      CalendarStruct(MQL5Calendar_Table).name,CalendarStruct(TimeSchedule_Table).name,
                                      Request_Events(CEvent1),Request_Events(CEvent2),Request_Events(CEvent3),
                                      Request_Events(CEvent4),Request_Events(CEvent5));
            break;
         case News_Select_Settings://NEWS SETTINGS
            //--- Get filtered calendar DB data
            SqlRequest = StringFormat("Select MQ.EventId,MQ.Country,MQ.EventName,MQ.EventType,MQ.EventImportance,MQ.EventCurrency,"
                                      "MQ.EventCode,MQ.EventSector,MQ.EventForecast,MQ.EventPreValue,MQ.EventImpact,MQ.EventFrequency,"
                                      "TS.DST_UK,TS.DST_US,TS.DST_AU,TS.DST_NONE from %s MQ "
                                      "Inner Join %s TS on TS.ID=MQ.ID "
                                      "Where %s and %s and %s and %s and %s;",
                                      CalendarStruct(MQL5Calendar_Table).name,CalendarStruct(TimeSchedule_Table).name,
                                      Request_Importance(myImportance),Request_Frequency(myFrequency),
                                      Request_Sector(mySector),Request_Type(myType),Request_Currency(myCurrency));
            break;
         default://Unknown
            break;
        }
// ...

Función Request_Events(CustomEvent &CEvent):

  • Esta función genera una cláusula SQL WHERE para consultar la base de datos basándose en los identificadores de eventos personalizados almacenados en la estructura CustomEvent.
  • Comprueba si useEvents es verdadero. Si es así, añade cada identificador de evento de la matriz CEvent.EventIds[] a la consulta SQL.

   //--- Retrieve Sql request string for custom event ids
   string            Request_Events(CustomEvent &CEvent)
     {
      //--- Default request string
      string EventReq="MQ.EventId='0'";
      //--- Check if this Custom event should be included in the SQL request
      if(CEvent.useEvents)
        {
         //--- Get request for first event id
         EventReq=StringFormat("(MQ.EventId='%s'",
                               (CEvent.EventIds.Size()>0)?
                               CEvent.EventIds[0]:"0");
         //--- Iterate through remaining event ids and add to the SQL request
         for(uint i=1;i<CEvent.EventIds.Size();i++)
           {
            EventReq+=StringFormat(" OR MQ.EventId='%s'",CEvent.EventIds[i]);
           }
         EventReq+=")";
        }
      //--- Return SQL request for custom event ids
      return EventReq;
     }

Miembros de clase pública:

Se han realizado actualizaciones en las siguientes funciones: EconomicDetailsMemory, EconomicNextEvent e isEvent.

  • EconomicDetailsMemory: Obtiene valores de la base de datos del calendario en memoria.
  • EconomicNextEvent: Actualiza la variable de estructura con los datos del siguiente evento.
  • isEvent: Comprueba si está a punto de producirse un evento de noticias y modifica los parámetros pasados en consecuencia.

   //Public declarations accessable via a class's Object
public:
  // ...
   void              EconomicDetailsMemory(Calendar &NewsTime[],datetime date,bool ImpactRequired);//Gets values from the MQL5 DB Calendar in Memory
   void              EconomicNextEvent();//Will update UpcomingNews structure variable with the next event data
 // ...
   //--- Checks if a news event is occurring and modifies the parameters passed by reference
   bool              isEvent(uint SecondsPreEvent,string &Name,string &Importance,string &Code);

En la función EconomicDetailsMemory, el objetivo es recuperar datos de eventos del calendario económico de una base de datos en memoria (DBMemory) para una fecha específica, teniendo en cuenta opcionalmente el impacto del evento, y almacenar los datos en una matriz NewsTime[].

  • La función obtiene los detalles de los eventos económicos de una base de datos para una fecha específica y los almacena en la matriz NewsTime[].
  • Si ImpactRequired es verdadero, recupera los valores anteriores y previstos del evento y asigna el impacto basándose en datos históricos.
  • Si ImpactRequired es falso, simplemente recupera los datos del día actual y del próximo evento.
  • Los resultados se obtienen mediante una consulta SQL preparada y se almacenan en la matriz NewsTime[], cuyo tamaño se ajusta dinámicamente en función del número de eventos recuperados.

//+------------------------------------------------------------------+
//|Gets values from the MQL5 DB Calendar in Memory                   |
//+------------------------------------------------------------------+
void CNews::EconomicDetailsMemory(Calendar &NewsTime[],datetime date,bool ImpactRequired)
  {
//--- SQL query to retrieve news data for a certain date
   string request_text;
//--- Check if Event impact is required for retrieving news events
   if(ImpactRequired)
     {
      request_text=StringFormat("WITH DAILY_EVENTS AS(SELECT M.EVENTID as 'E_ID',M.COUNTRY,M.EVENTNAME as 'Name',M.EVENTTYPE as"
                                " 'Type',M.EVENTIMPORTANCE as 'Importance',M.%s as 'Time',M.EVENTCURRENCY as 'Currency',M.EVENTCODE"
                                " as 'Code',M.EVENTSECTOR as 'Sector',M.EVENTFORECAST as 'Forecast',M.EVENTPREVALUE as 'PREVALUE',"
                                "M.EVENTFREQUENCY as 'Freq' FROM %s M WHERE DATE(REPLACE(Time,'.','-'))=DATE(REPLACE('%s','.','-'))"
                                " AND (Forecast<>'None' AND Prevalue<>'None')),DAILY_IMPACT AS(SELECT DE.E_ID,DE.COUNTRY,DE.Name,"
                                "DE.Type,DE.Importance,DE.Time,DE.Currency,DE.Code,DE.Sector,DE.Forecast,DE.Prevalue,DE.Freq,"
                                "MC.EVENTIMPACT as 'IMPACT', RANK() OVER(PARTITION BY DE.E_ID,DE.Time ORDER BY MC.%s DESC)DateOrder"
                                " FROM %s MC INNER JOIN DAILY_EVENTS DE on DE.E_ID=MC.EVENTID WHERE DATE(REPLACE(MC.%s,'.','-'))<"
                                "DATE(REPLACE(DE.Time,'.','-')) AND DATE(REPLACE(MC.%s,'.','-'))>=DATE(REPLACE(DE.Time,'.','-'),"
                                "'-24 months') AND (MC.EVENTFORECAST<>'None' AND MC.EVENTPREVALUE<>'None' AND (CASE WHEN Forecast>"
                                "Prevalue THEN 'more' WHEN Forecast<Prevalue THEN 'less' ELSE 'equal' END)=(CASE WHEN MC.EVENTFORECAST"
                                ">MC.EVENTPREVALUE THEN 'more' WHEN MC.EVENTFORECAST<MC.EVENTPREVALUE THEN 'less' ELSE 'equal' END)) "
                                "ORDER BY MC.%s),DAILY_EVENTS_RECORDS AS(SELECT * FROM DAILY_IMPACT WHERE DateOrder=1 ORDER BY Time"
                                " ASC),NEXT_EVENT AS(SELECT M.EVENTID as 'E_ID',M.COUNTRY,M.EVENTNAME as 'Name',M.EVENTTYPE as 'Type',"
                                "M.EVENTIMPORTANCE as 'Importance',M.%s as 'Time',M.EVENTCURRENCY as 'Currency',M.EVENTCODE as 'Code',"
                                "M.EVENTSECTOR as 'Sector',M.EVENTFORECAST as 'Forecast',M.EVENTPREVALUE as 'PREVALUE',M.EVENTFREQUENCY"
                                " as 'Freq' FROM %s M WHERE DATE(REPLACE(Time,'.','-'))>DATE(REPLACE('%s','.','-'))  AND (Forecast<>"
                                "'None' AND Prevalue<>'None' AND DATE(REPLACE(Time,'.','-'))<=DATE(REPLACE('%s','.','-'),'+60 days'))),"
                                "NEXT_IMPACT AS(SELECT NE.E_ID,NE.COUNTRY,NE.Name,NE.Type,NE.Importance,NE.Time,NE.Currency,NE.Code"
                                ",NE.Sector,NE.Forecast,NE.Prevalue,NE.Freq,MC.EVENTIMPACT as 'IMPACT',RANK() OVER(PARTITION BY "
                                "NE.E_ID,NE.Time ORDER BY MC.%s DESC)DateOrder FROM %s MC INNER JOIN NEXT_EVENT NE on NE.E_ID=MC.EVENTID "
                                "WHERE DATE(REPLACE(MC.%s,'.','-'))<DATE(REPLACE(NE.Time,'.','-')) AND DATE(REPLACE(MC.%s,'.','-'))>="
                                "DATE(REPLACE(NE.Time,'.','-'),'-24 months') AND (MC.EVENTFORECAST<>'None' AND MC.EVENTPREVALUE<>'None'"
                                " AND (CASE WHEN Forecast>Prevalue THEN 'more' WHEN Forecast<Prevalue THEN 'less' ELSE 'equal' END)="
                                "(CASE WHEN MC.EVENTFORECAST>MC.EVENTPREVALUE THEN 'more' WHEN MC.EVENTFORECAST<MC.EVENTPREVALUE THEN "
                                "'less' ELSE 'equal' END)) ORDER BY MC.%s),NEXT_EVENT_RECORD AS(SELECT * FROM NEXT_IMPACT WHERE "
                                "DateOrder=1 ORDER BY Time ASC LIMIT 1),ALL_EVENTS AS(SELECT * FROM NEXT_EVENT_RECORD UNION ALL "
                                "SELECT * FROM DAILY_EVENTS_RECORDS)SELECT E_ID,Country,Name,Type,Importance,Time,Currency,Code,"
                                "Sector,Forecast,Prevalue,Impact,Freq FROM ALL_EVENTS GROUP BY Time ORDER BY Time Asc;",
                                EnumToString(MySchedule),DBMemory.name,TimeToString(date),EnumToString(MySchedule),DBMemory.name,
                                EnumToString(MySchedule),EnumToString(MySchedule),EnumToString(MySchedule),EnumToString(MySchedule)
                                ,DBMemory.name,TimeToString(date),TimeToString(date),EnumToString(MySchedule),DBMemory.name,
                                EnumToString(MySchedule),EnumToString(MySchedule),EnumToString(MySchedule));
     }
   else
     {
      /*
      Within this request we select all the news events that will occur or have occurred in the current day and the next news
      event after the current day
      */
      request_text=StringFormat("WITH DAILY_EVENTS AS(SELECT M.EVENTID as 'E_ID',M.COUNTRY,M.EVENTNAME as 'Name',M.EVENTTYPE as"
                                " 'Type',M.EVENTIMPORTANCE as 'Importance',M.%s as 'Time',M.EVENTCURRENCY as 'Currency',M.EVENTCODE"
                                " as 'Code',M.EVENTSECTOR as 'Sector',M.EVENTFORECAST as 'Forecast',M.EVENTPREVALUE as 'PREVALUE'"
                                ",M.EVENTFREQUENCY as 'Freq',M.EVENTIMPACT as 'Impact' FROM %s M WHERE DATE(REPLACE(Time,'.','-'))"
                                "=DATE(REPLACE('%s','.','-'))),DAILY_EVENTS_RECORDS AS(SELECT * FROM DAILY_EVENTS ORDER BY Time ASC)"
                                ",NEXT_EVENT AS(SELECT M.EVENTID as 'E_ID',M.COUNTRY,M.EVENTNAME as 'Name',M.EVENTTYPE as 'Type',"
                                "M.EVENTIMPORTANCE as 'Importance',M.%s as 'Time',M.EVENTCURRENCY as 'Currency',M.EVENTCODE as "
                                "'Code',M.EVENTSECTOR as 'Sector',M.EVENTFORECAST as 'Forecast',M.EVENTPREVALUE as 'PREVALUE',"
                                "M.EVENTFREQUENCY as 'Freq',M.EVENTIMPACT as 'Impact' FROM %s M WHERE DATE(REPLACE(Time,'.','-'))"
                                ">DATE(REPLACE('%s','.','-')) AND (DATE(REPLACE(Time,'.','-'))<=DATE(REPLACE('%s','.','-'),"
                                "'+60 days'))),NEXT_EVENT_RECORD AS(SELECT * FROM NEXT_EVENT ORDER BY Time ASC LIMIT 1),"
                                "ALL_EVENTS AS(SELECT * FROM NEXT_EVENT_RECORD UNION ALL SELECT * FROM "
                                "DAILY_EVENTS_RECORDS)SELECT * FROM ALL_EVENTS GROUP BY Time ORDER BY Time Asc;",
                                EnumToString(MySchedule),DBMemory.name,TimeToString(date),EnumToString(MySchedule),DBMemory.name,
                                TimeToString(date),TimeToString(date));
     }
// ...

Firma de la función

  • Argumentos:
    • Calendar &NewsTime[]: Una matriz de estructuras Calendar (cada una con los detalles del evento), que se rellenará con los datos recuperados.
    • datetime date: La fecha específica para la que se recuperan los eventos económicos.
    • bool ImpactRequired: Indicador que señala si el impacto del evento debe tenerse en cuenta en la consulta.

Construcción de consultas SQL basadas en requisitos de impacto

La consulta SQL varía en función de si ImpactRequired está establecido en verdadero o falso. Esto es así cuando los acontecimientos de noticias verdaderos requieren un impacto del acontecimiento para la dirección de la operación, mientras que cuando son falsos, el impacto del acontecimiento no es necesario, ya que la dirección del acontecimiento no es necesaria para abrir una operación.

A. Si ImpactRequired es verdadero

Esta consulta es más compleja e implica varias partes:

  • La consulta recupera los eventos económicos para la fecha dada y también tiene en cuenta el próximo evento después del día actual.
  • Busca eventos anteriores dentro de los últimos 24 meses en los que se disponga tanto de la previsión como del valor previo y los compara con el evento actual.
  • Si el valor previsto es mayor que el valor previo (o viceversa) o incluso igual, se compara con el evento histórico que tiene la misma tendencia (previsión > valor previo o previsión < valor previo o previsión = valor previo).
  • Asigna el impacto del evento pasado al evento actual.

A continuación se describe cómo se construye la consulta:

"WITH DAILY_EVENTS AS(...) , DAILY_IMPACT AS(...) , NEXT_EVENT AS(...), NEXT_IMPACT AS(...), 
ALL_EVENTS AS(...) SELECT * FROM ALL_EVENTS GROUP BY Time ORDER BY Time Asc;"

  • DAILY_EVENTS: Selecciona todos los eventos económicos para la fecha especificada en el calendario. Se seleccionan los eventos con un pronóstico y un valor previo válidos.
  • DAILY_IMPACT: Esto encuentra eventos históricos (en los últimos 24 meses) en los que la tendencia de la previsión y el valor previo (mayor/menor o igual) es similar a la del evento actual. Clasifica los eventos por fecha para encontrar el evento coincidente más reciente y asigna su impacto al evento actual.
  • NEXT_EVENT: Selecciona el próximo evento después del día actual.
  • NEXT_IMPACT: De forma similar a DAILY_IMPACT, recupera el evento pasado más reciente que coincide con la tendencia del pronóstico/valor previo y asigna su impacto al siguiente evento.
  • ALL_EVENTS: Combina DAILY_EVENTS_RECORDS (para el día actual) y NEXT_EVENT_RECORD (para el próximo evento) y los ordena por hora.

B. Si ImpactRequired es falso

Si no se requiere el impacto, la consulta es más sencilla:

  • Recupera todos los eventos del día actual y el siguiente evento después del día actual (en un plazo de 60 días).

Esquema de la consulta SQL:

"WITH DAILY_EVENTS AS(...) , NEXT_EVENT AS(...), ALL_EVENTS AS(...) SELECT * FROM ALL_EVENTS GROUP BY Time ORDER BY Time Asc;"

  • DAILY_EVENTS: Recupera los eventos económicos del día actual.
  • NEXT_EVENT: Recupera el próximo evento después del día actual dentro de los próximos 60 días.
  • ALL_EVENTS: Combina tanto los eventos diarios como el próximo evento y los ordena por hora.

Ejecución de consultas SQL

int request = DatabasePrepare(DBMemoryConnection, request_text);

  • DatabasePrepare: Prepara la consulta SQL para su ejecución. El resultado se almacena en request, que es un identificador de la consulta. Este controlador se utilizará para recuperar los datos.
  • Gestión de errores: Si la solicitud falla (request == INVALID_HANDLE), se muestra el mensaje de error y la consulta SQL con fines de depuración.

Leyendo los resultados

Calendar ReadDB_Data;
ArrayRemove(NewsTime, 0, WHOLE_ARRAY);
for (int i = 0; DatabaseReadBind(request, ReadDB_Data); i++)
{
    ArrayResize(NewsTime, i + 1, i + 2);
    NewsTime[i] = ReadDB_Data;
}

  • ArrayRemove: Borra la matriz NewsTime[] para prepararla para nuevos datos.
  • DatabaseReadBind: Obtiene los resultados de la consulta preparada, vinculando cada fila de resultados a la variable ReadDB_Data, que es una estructura Calendar.
  • ArrayResize: Cambia el tamaño de la matriz NewsTime[] para acomodar los nuevos datos. Por cada fila devuelta por DatabaseReadBind, la matriz crece en 1 elemento.
  • NewsTime[i] = ReadDB_Data: Copia los datos recuperados en la matriz NewsTime[].

Finalización de la consulta

DatabaseFinalize(request);

  • DatabaseFinalize: Limpia los recursos asignados por DatabasePrepare y libera el controlador de consulta.

La función EconomicNextEvent se encarga de identificar el próximo evento de noticias económicas y actualizar la variable UpcomingNews con sus detalles.

  • La función revisa todos los eventos en CalendarArray y encuentra el próximo evento, según la hora del servidor (TimeTradeServer()).
  • Actualiza la estructura UpcomingNews con los detalles de este próximo evento.
  • La lógica garantiza que solo se tengan en cuenta los eventos futuros (en relación con la hora del servidor) y se seleccione el evento más próximo.

//+------------------------------------------------------------------+
//|Will update UpcomingNews structure variable with the next news    |
//|event data                                                        |
//+------------------------------------------------------------------+
void CNews::EconomicNextEvent()
  {
//--- Declare unassigned Calendar structure variable Next
   Calendar Next;
//--- assign empty values to Calendar structure variable UpcomingNews
   UpcomingNews = Next;
//--- assign default date
   datetime NextEvent=0;
//--- Iterate through CalendarArray to retrieve news events
   for(uint i=0;i<CalendarArray.Size();i++)
     {
      //--- Check for next earliest news event from CalendarArray
      if((NextEvent==0)||(TimeTradeServer()<datetime(CalendarArray[i].EventDate)
                          &&NextEvent>datetime(CalendarArray[i].EventDate))||(NextEvent<TimeTradeServer()))
        {
         //--- assign values from the CalendarArray
         NextEvent = datetime(CalendarArray[i].EventDate);
         Next = CalendarArray[i];
        }
     }
//--- assign the next news event data into UpcomingNews variable
   UpcomingNews = Next;
  }

Declarar estructura de calendario sin asignar

Calendar Next;

  • La variable Next se declara como una estructura Calendar (una estructura personalizada que contiene detalles del evento, como la fecha, el nombre, el país, etc.).
  • Inicialmente, no está asignado y más adelante contendrá los datos del próximo evento económico.

Asignar valores vacíos a UpcomingNews

UpcomingNews = Next;

  • UpcomingNews es una variable global o de clase (otra estructura de Calendar) que almacena los detalles del próximo evento.
  • Al inicio, se restablece a los valores predeterminados (vacíos) de la variable Next.

Asignar fecha predeterminada

datetime NextEvent = 0;

  • La variable NextEvent se inicializa en 0, lo que significa que aún no se ha asignado ningún evento.
  • NextEvent almacenará la marca de tiempo (en formato fecha y hora) del próximo evento económico durante el bucle.

Iterar a través del CalendarArray

for (uint i = 0; i < CalendarArray.Size(); i++)

  • CalendarArray es una matriz que contiene los detalles de los eventos económicos.
  • El bucle «for» recorre cada elemento de esta matriz (cada uno de los cuales representa un evento) y comprueba si el evento cumple los requisitos para ser el próximo evento.

Comprueba las condiciones para el próximo evento.

if ((NextEvent == 0) || (TimeTradeServer() < datetime(CalendarArray[i].EventDate) && 
NextEvent > datetime(CalendarArray[i].EventDate)) || (NextEvent < TimeTradeServer()))

Esta instrucción «if» comprueba varias condiciones para determinar si el evento actual en la matriz (CalendarArray[i]) es el siguiente evento de noticias:

  • First Condition: (NextEvent == 0)
    • Si NextEvent sigue siendo 0 (aún no se ha asignado ningún evento), el evento actual se seleccionará como el siguiente evento.
  • Segunda condición: (TimeTradeServer() < datetime(CalendarArray[i].EventDate) && NextEvent > datetime(CalendarArray[i].EventDate))
    • Esto comprueba si el evento actual en la matriz (CalendarArray[i]) ocurre después de la hora actual del servidor (TimeTradeServer()) y es anterior al evento almacenado actualmente en NextEvent. Si es verdadero, el evento actual se convierte en el siguiente evento.
  • Tercera condición: (NextEvent < TimeTradeServer())
    • Si el evento almacenado actualmente en NextEvent ya ha ocurrido (es pasado), la función continúa buscando un evento futuro válido.

Asignar valores desde CalendarArray

NextEvent = datetime(CalendarArray[i].EventDate);
Next = CalendarArray[i];

  • Si se cumple alguna de las condiciones, el evento actual en CalendarArray[i] se determina como el siguiente evento:
    • NextEvent se actualiza con la fecha del evento actual.
    • A continuación, se actualiza para incluir todos los detalles (fecha, nombre, tipo, etc.) del evento actual.

Asignar el próximo evento a UpcomingNews

UpcomingNews = Next;

  • Una vez que el bucle termina de iterar a través de CalendarArray, la variable UpcomingNews se actualiza con los detalles del próximo evento (almacenado en Next).
  • La función garantiza que el primer evento futuro encontrado, en relación con la hora actual del servidor, se almacene en UpcomingNews.

En la función isEvent se comprueba si un evento de noticias está a punto de ocurrir o está ocurriendo actualmente dentro de un intervalo de tiempo específico. El propósito de esta función es comprobar si algún evento de noticias del CalendarArray está ocurriendo o está a punto de ocurrir, basándose en un desfase temporal. Si se encuentra un evento de este tipo, proporciona detalles sobre el evento, como su nombre, importancia y código.

  • Esta función recorre el CalendarArray (que contiene los datos de los eventos económicos) y comprueba si algún evento está ocurriendo o está a punto de ocurrir dentro de un intervalo de tiempo definido por SecondsPreEvent.
  • Si se encuentra un evento de este tipo, actualiza el nombre, la importancia y el código con los detalles del evento y devuelve verdadero.
  • Si no se encuentra ningún evento dentro del intervalo de tiempo definido, devuelve falso y deja Name, Importance y Code sin cambios (o establecidos en el valor predeterminado/NULL).

//+------------------------------------------------------------------+
//|Checks if News is event is about to occur or is occurring         |
//+------------------------------------------------------------------+
bool CNews::isEvent(uint SecondsPreEvent,string &Name,string &Importance,string &Code)
  {
//--- assign default value
   Name=NULL;
//--- Iterate through CalendarArray
   for(uint i=0;i<CalendarArray.Size();i++)
     {
      //--- Check if news event is within a timespan
      if(CTime.TimeIsInRange(CTime.TimeMinusOffset(datetime(CalendarArray[i].EventDate),SecondsPreEvent),
                             CTime.TimePlusOffset(datetime(CalendarArray[i].EventDate),59)))
        {
         //--- assign appropriate CalendarArray values
         Name=CalendarArray[i].EventName;
         Importance=CalendarArray[i].EventImportance;
         Code=CalendarArray[i].EventCode;
         //--- news event is currently within the timespan
         return true;
        }
     }
//--- no news event is within the current timespan.
   return false;
  }

Parámetros:

  • uint SecondsPreEvent: El número de segundos antes del evento durante los cuales el evento se considera «próximo».
  • string &Name: Una referencia a una cadena que almacenará el nombre del evento si se encuentra dentro del intervalo de tiempo definido.
  • string &Importance: Una referencia a una cadena que almacenará el nivel de importancia del evento si se encuentra.
  • string &Code: Una referencia a una cadena que almacenará el código del evento.

Asignar valor predeterminado a Name

Name = NULL;

  • La variable Name se inicializa con NULL. Si no se encuentra ningún evento dentro del intervalo de tiempo especificado, Name permanecerá NULL.
  • Esto garantiza que el nombre solo se actualice si se encuentra un evento dentro del intervalo de tiempo.

Iterar a través del CalendarArray

for (uint i = 0; i < CalendarArray.Size(); i++)

  • El bucle recorre todos los elementos de CalendarArray, donde cada elemento representa un evento de noticias.
  • El bucle comprobará cada evento para ver si se encuentra dentro del intervalo de tiempo especificado alrededor de la hora actual.

Comprueba si el evento se encuentra dentro del intervalo de tiempo.

if (CTime.TimeIsInRange(CTime.TimeMinusOffset(datetime(CalendarArray[i].EventDate), SecondsPreEvent),
                        CTime.TimePlusOffset(datetime(CalendarArray[i].EventDate), 59)))

  • CTime.TimeMinusOffset(datetime(CalendarArray[i].EventDate), SecondsPreEvent):
    • Esta llamada a la función comprueba si la fecha del evento (CalendarArray[i].EventDate) menos el valor SecondsPreEvent es anterior al presente.
    • Básicamente, define el límite inferior de la ventana de tiempo (cuántos segundos antes del evento).
  • CTime.TimePlusOffset(datetime(CalendarArray[i].EventDate), 59):
    • Esta función comprueba si la fecha del evento más 59 segundos se encuentra en el futuro, definiendo el límite superior de la ventana de tiempo (cuánto tiempo se considera que el evento está activo).

  • La función CTime.TimeIsInRange comprueba si la hora actual se encuentra dentro de este intervalo de tiempo. Si la hora actual se encuentra dentro de este intervalo, significa que el evento está a punto de ocurrir o ya está ocurriendo.

Asignar valores desde CalendarArray

Name = CalendarArray[i].EventName;
Importance = CalendarArray[i].EventImportance;
Code = CalendarArray[i].EventCode;

  • Si se determina que el evento se encuentra dentro del intervalo de tiempo especificado, los detalles relevantes (nombre del evento, importancia y código) se extraen del CalendarArray y se asignan a los parámetros de referencia:
    • Name: El nombre del evento de noticias.
    • Importance: El nivel de importancia del acontecimiento.
    • Code: El código del evento.

Devuelve verdadero si se encuentra un evento.

return true;

  • Si se encuentra un evento de noticias dentro del intervalo de tiempo, la función devuelve verdadero, lo que indica que un evento relevante está ocurriendo actualmente o está a punto de ocurrir.

Devuelve falso si no se encuentra ningún evento.

return false;

  • Si el bucle termina de iterar a través de todos los eventos en CalendarArray y no se encuentra ningún evento dentro del intervalo de tiempo especificado, la función devuelve false, lo que indica que no se está produciendo ningún evento relevante.

Constructor CNews::CNews(void):

  • Inicializa la clase configurando las sentencias SQL DROP, CREATE e INSERT para los diferentes componentes del calendario económico.
    • Tables: Define tablas como AutoDST, Record, TimeSchedule y MQL5Calendar.
    • Views: Define vistas para diferentes horarios de horario de verano (Calendar_AU, Calendar_UK, etc.), información sobre eventos, divisas y fechas de eventos recientes/próximos.
    • Triggers: Define desencadenadores como OnlyOne_AutoDST y OnlyOne_Record para garantizar que solo exista un registro en tablas específicas.

Cada componente (table, view o trigger) se inicializa con sus respectivos comandos SQL, incluyendo la creación, inserción y eliminación de registros.

Creación de vistas SQL:

  • Para cada componente del calendario y del horario DST, se definen vistas SQL específicas para estructurar los datos según diversos criterios (por ejemplo, por importancia del evento, moneda o fecha del evento). Por ejemplo:

    • Vista de próximos eventos: Muestra las fechas de los próximos eventos junto con el día de la semana y los detalles del evento.
    • Vista de eventos recientes: similar a la vista de eventos próximos, pero muestra las fechas de los eventos recientes.

Desencadenador SQL:

  • Los desencadenadores se utilizan para garantizar que solo exista un registro en las tablas AutoDST y Record en un momento dado, eliminando los registros existentes antes de una operación de inserción.

//+------------------------------------------------------------------+
//|Constructor                                                       |
//+------------------------------------------------------------------+
CNews::CNews(void):DropRequest("PRAGMA foreign_keys = OFF; "
                                  "PRAGMA secure_delete = ON; "
                                  "Drop %s IF EXISTS '%s'; "
                                  "Vacuum; "
                                  "PRAGMA foreign_keys = ON;")//Sql drop statement
  {
// ...
   string views[] = {"AU","NONE","UK","US"};
//-- Sql statement for creating the table views for each DST schedule
   string view_sql = "CREATE VIEW IF NOT EXISTS Calendar_%s "
                     "AS "
                     "SELECT C.Eventid as 'ID',C.Eventname as 'Name',C.Country as 'Country', "
                     "(CASE WHEN Date(REPLACE(T.DST_%s,'.','-'))<R.Date THEN CONCAT(T.DST_%s,' | Yesterday') "
                     "WHEN Date(REPLACE(T.DST_%s,'.','-'))=R.Date THEN CONCAT(T.DST_%s,' | Today') "
                     "WHEN Date(REPLACE(T.DST_%s,'.','-'))>R.Date THEN CONCAT(T.DST_%s,' | Tomorrow') END) as "
                     "'Date',C.EventCurrency as 'Currency',Replace(C.EventImportance,'CALENDAR_IMPORTANCE_','')"
                     " as 'Importance' from MQL5Calendar C,Record R Inner join TimeSchedule T on C.ID=T.ID Where"
                     " DATE(REPLACE(T.DST_%s,'.','-'))>=DATE(R.Date,'-1 day') AND DATE(REPLACE(T.DST_%s,'.','-'))"
                     "<=DATE(R.Date,'+1 day') Order by T.DST_%s Asc;";
// ...
//--- initializing properties for the EventInfo view
   CalendarContents[5].Content = EventInfo_View;
   CalendarContents[5].name = "Event Info";
   CalendarContents[5].sql = "CREATE VIEW IF NOT EXISTS 'Event Info' "
                             "AS SELECT DISTINCT MC.EVENTID as 'ID',MC.COUNTRY as 'Country',MC.EVENTNAME as 'Name',"
                             "REPLACE(MC.EVENTTYPE,'CALENDAR_TYPE_','') as 'Type',REPLACE(MC.EVENTSECTOR,'CALENDAR_SECTOR_','') as 'Sector',"
                             "REPLACE(MC.EVENTIMPORTANCE,'CALENDAR_IMPORTANCE_','') as 'Importance',MC.EVENTCURRENCY as 'Currency',"
                             "REPLACE(MC.EVENTFREQUENCY,'CALENDAR_FREQUENCY_','') as 'Frequency',MC.EVENTCODE as 'Code' "
                             "FROM MQL5Calendar MC ORDER BY \"Country\" Asc,"
                             "CASE \"Importance\" WHEN 'HIGH' THEN 1 WHEN 'MODERATE' THEN 2 WHEN 'LOW' THEN 3 ELSE 4 END,\"Sector\" Desc;";
   CalendarContents[5].tbl_name = "Event Info";
   CalendarContents[5].type = "view";
// ...
//--- initializing properties for the UpcomingEventInfo view
   CalendarContents[7].Content = UpcomingEventInfo_View;
   CalendarContents[7].name = "Upcoming Event Dates";
   CalendarContents[7].sql = "CREATE VIEW IF NOT EXISTS 'Upcoming Event Dates' AS WITH UNIQUE_EVENTS AS(SELECT DISTINCT M.EVENTID as 'E_ID',"
                             "M.COUNTRY as 'Country',M.EVENTNAME as 'Name',M.EVENTCURRENCY as 'Currency' FROM 'MQL5Calendar' M),"
                             "INFO_DATE AS(SELECT E_ID,Country,Name,Currency,(SELECT T.DST_NONE as 'Time' FROM MQL5Calendar M,"
                             "Record R INNER JOIN TIMESCHEDULE T ON T.ID=M.ID WHERE DATE(REPLACE(Time,'.','-'))>R.Date AND "
                             "E_ID=M.EVENTID ORDER BY Time ASC LIMIT 1) as 'Next Event Date' FROM UNIQUE_EVENTS) SELECT E_ID "
                             "as 'ID',Country,Name,Currency,(CASE WHEN \"Next Event Date\" IS NULL THEN 'Unknown' ELSE "
                             "\"Next Event Date\" END) as 'Upcoming Date',(CASE WHEN \"Next Event Date\"<>'Unknown' THEN "
                             "(case cast (strftime('%w', DATE(REPLACE(\"Next Event Date\",'.','-'))) as integer) WHEN 0 THEN"
                             " 'Sunday' WHEN 1 THEN 'Monday' WHEN 2 THEN 'Tuesday' WHEN 3 THEN 'Wednesday' WHEN 4 THEN 'Thursday'"
                             " WHEN 5 THEN 'Friday' ELSE 'Saturday' END)  ELSE 'Unknown' END) as 'Day' FROM INFO_DATE Order BY "
                             "\"Upcoming Date\" ASC;";
   CalendarContents[7].tbl_name = "Upcoming Event Dates";
   CalendarContents[7].type = "view";
//--- initializing properties for the RecentEventInfo view
   CalendarContents[8].Content = RecentEventInfo_View;
   CalendarContents[8].name = "Recent Event Dates";
   CalendarContents[8].sql = "CREATE VIEW IF NOT EXISTS 'Recent Event Dates' AS WITH UNIQUE_EVENTS AS(SELECT DISTINCT M.EVENTID"
                             " as 'E_ID',M.COUNTRY as 'Country',M.EVENTNAME as 'Name',M.EVENTCURRENCY as 'Currency'"
                             "FROM 'MQL5Calendar' M),INFO_DATE AS(SELECT E_ID,Country,Name,Currency,"
                             "(SELECT T.DST_NONE as 'Time' FROM MQL5Calendar M,Record R INNER JOIN TIMESCHEDULE T ON"
                             " T.ID=M.ID WHERE DATE(REPLACE(Time,'.','-'))<=R.Date AND E_ID=M.EVENTID ORDER BY Time DESC"
                             " LIMIT 1) as 'Last Event Date' FROM UNIQUE_EVENTS) SELECT E_ID as 'ID',Country,Name,Currency"
                             ",\"Last Event Date\" as 'Recent Date',(case cast (strftime('%w', DATE(REPLACE(\"Last Event Date\""
                             ",'.','-'))) as integer) WHEN 0 THEN 'Sunday' WHEN 1 THEN 'Monday' WHEN 2 THEN 'Tuesday' WHEN 3 THEN"
                             " 'Wednesday' WHEN 4 THEN 'Thursday' WHEN 5 THEN 'Friday' ELSE 'Saturday' END) as 'Day' FROM INFO_DATE"
                             " Order BY \"Recent Date\" DESC;";
   CalendarContents[8].tbl_name = "Recent Event Dates";
   CalendarContents[8].type = "view";
// ...

La consulta siguiente se encarga de crear cuatro vistas similares pero diferentes: Calendar_AU, Calendar_NONE, Calendar_UK y Calendar_US. Cada una de estas vistas extrae datos de tres tablas: MQL5Calendar, Record y TimeSchedule. Estas consultas crean vistas que muestran los detalles de los eventos (ID, nombre, país, fecha, divisa e importancia) para diferentes zonas horarias (Australia, Ninguna/Predeterminada, Reino Unido y EE. UU.). La fecha de cada evento se etiqueta según si ocurrió ayer, hoy o mañana en relación con la fecha actual, y los resultados se filtran para mostrar los eventos que tienen lugar en el plazo de un día desde la fecha actual. Las vistas se ordenan por la fecha del evento en la zona horaria correspondiente.

Utilizaremos la vista Calendar_AU para explicarlo.

Consulta totalmente visible:

CREATE VIEW IF NOT EXISTS Calendar_AU AS SELECT C.Eventid as 'ID',C.Eventname as 'Name',C.Country as 'Country', 
(CASE WHEN Date(REPLACE(T.DST_AU,'.','-'))<R.Date THEN CONCAT(T.DST_AU,' | Yesterday') WHEN Date(REPLACE(T.DST_AU,'.','-'))=R.Date 
THEN CONCAT(T.DST_AU,' | Today') WHEN Date(REPLACE(T.DST_AU,'.','-'))>R.Date THEN CONCAT(T.DST_AU,' | Tomorrow') END) as 'Date',
C.EventCurrency as 'Currency',Replace(C.EventImportance,'CALENDAR_IMPORTANCE_','') as 'Importance' from MQL5Calendar C,
Record R Inner join TimeSchedule T on C.ID=T.ID Where DATE(REPLACE(T.DST_AU,'.','-'))>=DATE(R.Date,'-1 day') AND 
DATE(REPLACE(T.DST_AU,'.','-'))<=DATE(R.Date,'+1 day') Order by T.DST_AU Asc;

CREATE VIEW IF NOT EXISTS Calendar_AU, Esto crea una vista llamada Calendar_AU si aún no existe. Una vista es esencialmente una tabla virtual creada a partir de una consulta, que permite recuperar datos sin necesidad de almacenarlos de nuevo.

Cláusula SELECT:

SELECT 
    C.Eventid as 'ID',
    C.Eventname as 'Name',
    C.Country as 'Country',
    (CASE 
        WHEN Date(REPLACE(T.DST_AU,'.','-')) < R.Date THEN CONCAT(T.DST_AU, ' | Yesterday') 
        WHEN Date(REPLACE(T.DST_AU,'.','-')) = R.Date THEN CONCAT(T.DST_AU, ' | Today') 
        WHEN Date(REPLACE(T.DST_AU,'.','-')) > R.Date THEN CONCAT(T.DST_AU, ' | Tomorrow') 
    END) as 'Date',
    C.EventCurrency as 'Currency',
    Replace(C.EventImportance,'CALENDAR_IMPORTANCE_','') as 'Importance'

Esta parte de la consulta selecciona campos específicos de las tablas MQL5Calendar, Record y TimeSchedule y formatea los datos en consecuencia:

  • C.Eventid es el identificador del evento.
  • C.Eventname es el nombre del evento.
  • C. País es el país asociado al evento.
  • Se utiliza una instrucción CASE para comparar la fecha DST_AU (zona horaria australiana, almacenada en TimeSchedule) con R.Date (fecha actual de la tabla Record) para etiquetar el evento como «Yesterday», «Today» o «Tomorrow».
  • C.EventCurrency es la divisa relacionada con el evento.
  • Replace(C.EventImportance,“CALENDAR_IMPORTANCE_”,'') elimina el prefijo «CALENDAR_IMPORTANCE_» del campo EventImportance, extrayendo solo el nivel de importancia relevante (por ejemplo, «HIGH» o «LOW»).

Cláusula FROM:

FROM 
    MQL5Calendar C,
    Record R
    Inner join TimeSchedule T on C.ID=T.ID

  • La consulta extrae datos de tres tablas: MQL5Calendar (C), Record (R) y TimeSchedule (T).
  • Las tablas MQL5Calendar y Record forman parte de la cláusula FROM, y la tabla TimeSchedule se une mediante INNER JOIN con la condición C.ID=T.ID, lo que significa que el ID de la tabla MQL5Calendar debe coincidir con el ID de la tabla TimeSchedule.

Cláusula WHERE:

WHERE 
    DATE(REPLACE(T.DST_AU,'.','-')) >= DATE(R.Date,'-1 day') 
    AND DATE(REPLACE(T.DST_AU,'.','-')) <= DATE(R.Date,'+1 day')

  • Esto filtra los resultados para incluir solo los eventos en los que DST_AU (la fecha del evento en la zona horaria de Australia) se encuentra dentro de un día antes o después de la fecha actual (R.Date).

Cláusula ORDER BY:

ORDER BY T.DST_AU Asc;

  • Esto ordena los eventos en orden ascendente según DST_AU, la fecha en hora australiana.

Conceptos clave:

  • Formato de fecha y hora: La función REPLACE() se utiliza para sustituir los puntos . con guiones - en las columnas DST_, que se almacenan como cadenas que representan fechas (por ejemplo, 2024.09.23 se convierte en 2024-09-23).
  • Lógica condicional: La instrucción CASE comprueba si la fecha del evento (DST_AU, DST_NONE, DST_UK o DST_US) es anterior, igual o posterior a la fecha actual (R.Date) y añade una etiqueta en consecuencia («Yesterday», «Today» o «Tomorrow»).
  • Filtrado: La cláusula WHERE garantiza que solo se incluyan en la vista los eventos que se encuentren dentro del intervalo de un día antes o después de la fecha actual.
  • Extracción de la importancia: La función REPLACE() elimina el prefijo de la columna EventImportance para mostrar solo el nivel de importancia relevante (por ejemplo, «HIGH», «MEDIUM» o «LOW»).

Datos de salida de la vista Calendar_AU:

ID      	Name    					Country 	Date    			Currency        Importance
392080012       Autumnal Equinox Day    			Japan   	2024.09.22 02:00 | Yesterday    JPY     	NONE
554010007       Exports 					New Zealand     2024.09.23 00:45 | Today        NZD     	LOW
554010008       Imports 					New Zealand     2024.09.23 00:45 | Today        NZD     	LOW
// ...
710010010       Heritage Day    				South Africa    2024.09.24 02:00 | Tomorrow     ZAR     	NONE
36030005        RBA Rate Statement      			Australia       2024.09.24 07:30 | Tomorrow     AUD     	MODERATE
// ...

La consulta siguiente crea una vista denominada «Event Info» que selecciona y organiza la información de los eventos de la tabla MQL5Calendar. Esta vista extrae información distinta sobre los eventos de la tabla MQL5Calendar y formatea los datos para facilitar su lectura y análisis. Limpia los nombres de los campos eliminando los prefijos innecesarios (CALENDAR_TYPE_, CALENDAR_SECTOR_, etc.).

CREATE VIEW IF NOT EXISTS 'Event Info' AS SELECT DISTINCT MC.EVENTID as 'ID',MC.COUNTRY as 'Country',MC.EVENTNAME as 'Name',
REPLACE(MC.EVENTTYPE,'CALENDAR_TYPE_','') as 'Type',REPLACE(MC.EVENTSECTOR,'CALENDAR_SECTOR_','') as 'Sector',
REPLACE(MC.EVENTIMPORTANCE,'CALENDAR_IMPORTANCE_','') as 'Importance',MC.EVENTCURRENCY as 'Currency',
REPLACE(MC.EVENTFREQUENCY,'CALENDAR_FREQUENCY_','') as 'Frequency',MC.EVENTCODE as 'Code' FROM MQL5Calendar MC 
ORDER BY "Country" Asc,CASE "Importance" WHEN 'HIGH' THEN 1 WHEN 'MODERATE' THEN 2 WHEN 'LOW' THEN 3 ELSE 4 END,"Sector" Desc;

CREATE VIEW IF NOT EXISTS 'Event Info'

Esta parte crea una vista llamada «Event Info» si aún no existe. Una vista en SQL es una tabla virtual basada en el resultado de una consulta SELECT, lo que permite encapsular una consulta compleja y hacer referencia a ella como si fuera una tabla.

Cláusula SELECT DISTINCT:

SELECT DISTINCT 
    MC.EVENTID as 'ID',
    MC.COUNTRY as 'Country',
    MC.EVENTNAME as 'Name',
    REPLACE(MC.EVENTTYPE,'CALENDAR_TYPE_','') as 'Type',
    REPLACE(MC.EVENTSECTOR,'CALENDAR_SECTOR_','') as 'Sector',
    REPLACE(MC.EVENTIMPORTANCE,'CALENDAR_IMPORTANCE_','') as 'Importance',
    MC.EVENTCURRENCY as 'Currency',
    REPLACE(MC.EVENTFREQUENCY,'CALENDAR_FREQUENCY_','') as 'Frequency',
    MC.EVENTCODE as 'Code'

Esta sección recupera filas distintas (eliminando duplicados) de la tabla MQL5Calendar (MC es un alias para esta tabla) y selecciona columnas específicas para formar la vista.

Campos seleccionados:

  • MC.EVENTID como «ID»: Recupera el ID único de cada evento y lo renombra como «ID».
  • MC.COUNTRY como «Country»: Recupera el país asociado al evento.
  • MC.EVENTNAME como «Name»: Recupera el nombre del evento.

Transformación de datos con REPLACE():

Varios campos utilizan la función REPLACE() para eliminar prefijos como CALENDAR_TYPE_, CALENDAR_SECTOR_, CALENDAR_IMPORTANCE_ y CALENDAR_FREQUENCY_, dejando solo la parte significativa del campo:

  • REPLACE(MC.EVENTTYPE,'CALENDAR_TYPE_',") como «Type»: Elimina el prefijo CALENDAR_TYPE_ del campo EVENTTYPE para obtener un valor más limpio (por ejemplo, en lugar de CALENDAR_TYPE_CONSUMER, se obtiene CONSUMER).
  • REPLACE(MC.EVENTSECTOR,'CALENDAR_SECTOR_',") como «Sector»: Elimina el prefijo CALENDAR_SECTOR_ del campo EVENTSECTOR para obtener el nombre del sector.
  • REPLACE(MC.EVENTIMPORTANCE,'CALENDAR_IMPORTANCE_',") como «Importance»: Elimina el prefijo CALENDAR_IMPORTANCE_ del campo EVENTIMPORTANCE para mostrar el nivel de importancia (por ejemplo, HIGH, MODERATE, LOW).
  • MC.EVENTCURRENCY como «Currency»: Recupera la divisa involucrada en el evento.
  • REPLACE(MC.EVENTFREQUENCY,'CALENDAR_FREQUENCY_',") como «Frequency»: elimina el prefijo CALENDAR_FREQUENCY_ del campo EVENTFREQUENCY, proporcionando la frecuencia del evento (por ejemplo, MONTHLY o QUARTERLY).
  • MC.EVENTCODE como «Code»: recupera el código del evento sin ninguna transformación.

Cláusula FROM:

FROM MQL5Calendar MC

La consulta extrae datos de la tabla MQL5Calendar, cuyo alias es MC.

Cláusula ORDER BY:

ORDER BY 
    "Country" Asc,
    CASE "Importance"
        WHEN 'HIGH' THEN 1
        WHEN 'MODERATE' THEN 2
        WHEN 'LOW' THEN 3
        ELSE 4
    END,
    "Sector" Desc

Esta sección ordena los datos por varios campos para organizar la salida de la vista.

Ordenar por país (ascendente):

  • El primer criterio de clasificación es el país en orden ascendente (Asc), lo que significa que los eventos se agrupan y ordenan alfabéticamente por el campo del país.

Ordenar por importancia (orden personalizado):

  • La instrucción CASE ordena los niveles de importancia según una prioridad personalizada:
    • A la importancia «HIGH» se le asigna un valor de 1 (máxima prioridad).
    • A la importancia «MODERATE» se le asigna un valor de 2.
    • A la importancia «LOW» se le asigna un valor de 3.
    • A cualquier otro valor (por ejemplo, NONE) se le asigna un valor de 4, que es la prioridad más baja.

Esto significa que los eventos con importancia HIGH aparecerán primero, seguidos por los de importancia MODERATE, LOW y, por último, NONE.

Ordenar por sector (Descendente):

  • Por último, los eventos se ordenan por el campo Sector en orden descendente (Desc). Esto podría ordenar sectores como MONEY, CONSUMER, etc., en orden alfabético inverso.

Ejemplo de datos de salida de la vista «Event Info»:

ID      	Country 	Name    				Type    	Sector  	Importance      Currency  Frequency Code
36030008        Australia       RBA Interest Rate Decision      	INDICATOR       MONEY   	HIGH    	AUD       NONE      AU
36030006        Australia       RBA Governor Lowe Speech        	EVENT   	MONEY   	HIGH    	AUD       NONE      AU
36010003        Australia       Employment Change       		INDICATOR       JOBS    	HIGH    	AUD       MONTH     AU
// ...
36010036        Australia       Current Account 			INDICATOR       TRADE   	MODERATE        AUD       QUARTER   AU
36010011        Australia       Trade Balance   			INDICATOR       TRADE   	MODERATE        AUD       MONTH     AU
36010029        Australia       PPI q/q 				INDICATOR       PRICES  	MODERATE        AUD       QUARTER   AU
// ...
36010009        Australia       Exports m/m     			INDICATOR       TRADE   	LOW     	AUD       MONTH     AU
36010010        Australia       Imports m/m     			INDICATOR       TRADE   	LOW     	AUD       MONTH     AU
36010037        Australia       Net Exports Contribution        	INDICATOR       TRADE   	LOW     	AUD       QUARTER   AU
// ...
76020002        Brazil  	BCB Interest Rate Decision      	INDICATOR       MONEY   	HIGH    	BRL       NONE      BR
// ...

La consulta siguiente crea una vista denominada «Recent Event Dates», que proporciona un resumen de los eventos más recientes de la tabla MQL5Calendar, junto con el día de la semana en que se produjo el evento. Esta vista proporciona una lista de eventos recientes de la tabla MQL5Calendar, junto con el día de la semana en que se produjo el evento. Se centra en el evento más reciente de cada evento distinto del calendario.

CREATE VIEW IF NOT EXISTS 'Recent Event Dates' AS WITH UNIQUE_EVENTS AS(SELECT DISTINCT M.EVENTID as 'E_ID',M.COUNTRY as 'Country',
M.EVENTNAME as 'Name',M.EVENTCURRENCY as 'Currency'FROM 'MQL5Calendar' M),INFO_DATE AS(SELECT E_ID,Country,Name,Currency,
(SELECT T.DST_NONE as 'Time' FROM MQL5Calendar M,Record R INNER JOIN TIMESCHEDULE T ON T.ID=M.ID WHERE DATE(REPLACE(Time,'.','-'))
<=R.Date AND E_ID=M.EVENTID ORDER BY Time DESC LIMIT 1) as 'Last Event Date' FROM UNIQUE_EVENTS) SELECT E_ID as 'ID',Country,Name,
Currency,"Last Event Date" as 'Recent Date',(case cast (strftime('%w', DATE(REPLACE("Last Event Date",'.','-'))) as integer) WHEN 0 
THEN 'Sunday' WHEN 1 THEN 'Monday' WHEN 2 THEN 'Tuesday' WHEN 3 THEN 'Wednesday' WHEN 4 THEN 'Thursday' WHEN 5 THEN 'Friday' ELSE 
'Saturday' END) as 'Day' FROM INFO_DATE Order BY "Recent Date" DESC;

CREATE VIEW IF NOT EXISTS 'Recent Event Dates'

Esta parte crea una vista llamada «Recent Event Dates» si aún no existe.

Cláusula WITH: Expresiones de tabla comunes (Common Table Expressions, CTE)

Esta parte define dos expresiones de tabla comunes (CTE) que simplifican la lógica de la consulta al dividirla en pasos intermedios.

CTE 1: UNIQUE_EVENTS

WITH UNIQUE_EVENTS AS (
    SELECT DISTINCT 
        M.EVENTID as 'E_ID',
        M.COUNTRY as 'Country',
        M.EVENTNAME as 'Name',
        M.EVENTCURRENCY as 'Currency'
    FROM 'MQL5Calendar' M
)

  • Este CTE (UNIQUE_EVENTS) extrae eventos distintos de la tabla MQL5Calendar.
  • Selecciona el ID del evento (EVENTID), el país, el nombre y la divisa, asegurándose de que cada evento aparezca solo una vez en la lista (DISTINCT elimina las entradas duplicadas).

Columnas seleccionadas en UNIQUE_EVENTS:

  • M.EVENTID como «E_ID»: El identificador único del evento.
  • M.COUNTRY como «Country»: El país asociado al evento.
  • M.EVENTNAME como «Name»: El nombre del evento.
  • M.EVENTCURRENCY como «Currency»: La moneda asociada al evento.

CTE 2: INFO_DATE

INFO_DATE AS (
    SELECT 
        E_ID,
        Country,
        Name,
        Currency,
        (
            SELECT 
                T.DST_NONE as 'Time'
            FROM 
                MQL5Calendar M, 
                Record R 
                INNER JOIN TimeSchedule T ON T.ID = M.ID 
            WHERE 
                DATE(REPLACE(Time, '.', '-')) <= R.Date 
                AND E_ID = M.EVENTID 
            ORDER BY 
                Time DESC 
            LIMIT 1
        ) as 'Last Event Date'
    FROM UNIQUE_EVENTS
)

Este CTE (INFO_DATE) añade un campo de fecha (Last Event Date) a los eventos distintos del CTE anterior. Lo hace mediante:

  • Para cada evento único (E_ID, Country, Name, Currency), selecciona la fecha del evento más reciente de las tablas TimeSchedule y MQL5Calendar.

Explicación de la subconsulta:

  • La subconsulta recupera el campo DST_NONE de la tabla TimeSchedule (unida con las tablas MQL5Calendar y Record), que representa una marca de tiempo o la hora de un evento.
  • La condición DATE(REPLACE(Time, “.”, “-”)) <= R.Date garantiza que la fecha del evento (Time, tras sustituir los puntos . con guiones - para formar un formato de fecha válido) es menor o igual que la fecha actual en la tabla Record (R.Date).
  • Los eventos se ordenan en orden descendente por hora (ORDER BY Time DESC), y LIMIT 1 garantiza que solo se recupere la hora del evento más reciente.
Campos en INFO_DATE:
  • E_ID: El ID del evento de la tabla de tabla cruzada (CTE) UNIQUE_EVENTS.
  • Country: El país de la tabla CTE UNIQUE_EVENTS.
  • Name: El nombre del evento de la tabla CTE UNIQUE_EVENTS.
  • Currency: La moneda de la tabla CTE UNIQUE_EVENTS.
  • Last Event Date: La fecha más reciente de cada evento, obtenida de las tablas MQL5Calendar y TimeSchedule.

Consulta principal: Selección final y transformación

SELECT 
    E_ID as 'ID',
    Country,
    Name,
    Currency,
    "Last Event Date" as 'Recent Date',
    (
        CASE CAST (strftime('%w', DATE(REPLACE("Last Event Date", '.', '-'))) AS INTEGER)
        WHEN 0 THEN 'Sunday'
        WHEN 1 THEN 'Monday'
        WHEN 2 THEN 'Tuesday'
        WHEN 3 THEN 'Wednesday'
        WHEN 4 THEN 'Thursday'
        WHEN 5 THEN 'Friday'
        ELSE 'Saturday'
        END
    ) as 'Day'
FROM INFO_DATE
ORDER BY "Recent Date" DESC;

La parte principal de la consulta selecciona el resultado final del CTE INFO_DATE e incluye los siguientes campos:

  • E_ID as 'ID': El ID del evento, renombrado como «ID».
  • Country: El país asociado al evento.
  • Name: El nombre del evento.
  • Currency: La divisa relacionada con el evento.
  • «Last Event Date» como «Recent Date»: La fecha del evento más reciente, renombrada como «Recent Date».

Cálculo del día de la semana:

  • La consulta usa strftime('%w', DATE(REPLACE("Last Event Date", '.', '-'))) para convertir "Last Event Date" en un formato de fecha válido y obtener el día de la semana.
    • %w devuelve un número entero que representa el día de la semana, donde 0 = Sunday, 1 = Monday, ..., 6 = Saturday.
    • La instrucción CASE asigna el número entero al nombre del día correspondiente (por ejemplo, 0 -> Sunday, 1 -> Monday, etc.).
Esto proporciona un día de la semana legible para cada evento.

Ordenar los resultados:

ORDER BY "Recent Date" DESC

Los resultados se ordenan por «Recent Date» en orden descendente, lo que significa que los eventos más recientes aparecen en la parte superior de la lista.

Ejemplo de datos de salida de la vista «Recent Event Dates»:

ID      	Country 	Name    					Currency        Recent Date     	Day
554520001       New Zealand     CFTC NZD Non-Commercial Net Positions   	NZD     	2024.09.27 21:30        Friday
999520001       European Union  CFTC EUR Non-Commercial Net Positions   	EUR     	2024.09.27 21:30        Friday
392520001       Japan   	CFTC JPY Non-Commercial Net Positions   	JPY     	2024.09.27 21:30        Friday
// ...

La siguiente consulta crea una vista llamada «Upcoming Event Dates» para enumerar los próximos eventos de la tabla MQL5Calendar. Incluye la próxima fecha del evento y el día de la semana. La consulta tiene dos partes clave: Primero identifica eventos únicos y, a continuación, determina la próxima fecha programada para cada uno de esos eventos.

CREATE VIEW IF NOT EXISTS 'Upcoming Event Dates' AS WITH UNIQUE_EVENTS AS(SELECT DISTINCT M.EVENTID as 'E_ID',M.COUNTRY as 'Country',M.EVENTNAME
 as 'Name',M.EVENTCURRENCY as 'Currency' FROM 'MQL5Calendar' M),INFO_DATE AS(SELECT E_ID,Country,Name,Currency,(SELECT T.DST_NONE as 'Time' FROM
 MQL5Calendar M,Record R INNER JOIN TIMESCHEDULE T ON T.ID=M.ID WHERE DATE(REPLACE(Time,'.','-'))>R.Date AND E_ID=M.EVENTID ORDER BY Time ASC 
LIMIT 1) as 'Next Event Date' FROM UNIQUE_EVENTS) SELECT E_ID as 'ID',Country,Name,Currency,(CASE WHEN "Next Event Date" IS NULL THEN 'Unknown' 
ELSE "Next Event Date" END) as 'Upcoming Date',(CASE WHEN "Next Event Date"<>'Unknown' THEN (case cast (strftime('%w', 
DATE(REPLACE("Next Event Date",'.','-'))) as integer) WHEN 0 THEN 'Sunday' WHEN 1 THEN 'Monday' WHEN 2 THEN 'Tuesday' WHEN 3 THEN 'Wednesday' 
WHEN 4 THEN 'Thursday' WHEN 5 THEN 'Friday' ELSE 'Saturday' END)  ELSE 'Unknown' END) as 'Day' FROM INFO_DATE Order BY "Upcoming Date" ASC;

CREATE VIEW IF NOT EXISTS 'Upcoming Event Dates'

Esto crea una vista llamada «Upcoming Event Dates», pero solo si aún no existe.

Cláusula WITH: Expresiones de tabla comunes (Common Table Expressions, CTE)

La consulta utiliza expresiones de tabla comunes (CTE), que ayudan a desglosar consultas complejas en partes más simples y reutilizables. Aquí hay dos CTE: UNIQUE_EVENTS e INFO_DATE.

CTE 1: UNIQUE_EVENTS

WITH UNIQUE_EVENTS AS (
    SELECT DISTINCT 
        M.EVENTID as 'E_ID',
        M.COUNTRY as 'Country',
        M.EVENTNAME as 'Name',
        M.EVENTCURRENCY as 'Currency'
    FROM 'MQL5Calendar' M
)

  • Esta parte selecciona eventos únicos de la tabla MQL5Calendar.
  • Recupera el ID del evento (EVENTID), el país, el nombre y la divisa, asegurando que cada evento aparezca solo una vez utilizando DISTINCT.

El resultado de este CTE es un conjunto de eventos distintos con sus detalles asociados.

Columnas en UNIQUE_EVENTS:

  • E_ID: El identificador único del evento.
  • Country: El país al que está asociado el evento.
  • Name: El nombre del evento.
  • Currency: La divisa asociada al evento.

CTE 2: INFO_DATE

INFO_DATE AS (
    SELECT 
        E_ID,
        Country,
        Name,
        Currency,
        (
            SELECT 
                T.DST_NONE as 'Time'
            FROM 
                MQL5Calendar M, 
                Record R 
                INNER JOIN TimeSchedule T ON T.ID=M.ID 
            WHERE 
                DATE(REPLACE(Time, '.', '-')) > R.Date 
                AND E_ID = M.EVENTID 
            ORDER BY Time ASC 
            LIMIT 1
        ) as 'Next Event Date'
    FROM UNIQUE_EVENTS
)

Este CTE (INFO_DATE) obtiene la fecha del próximo evento para cada evento único.

  • Para cada evento (E_ID, Country, Name, Currency), busca la fecha del próximo evento en la tabla TimeSchedule (campo DST_NONE).

Explicación de la subconsulta:

  • La subconsulta recupera el campo DST_NONE de la tabla TimeSchedule, que representa la hora o la fecha del evento.
  • La condición DATE(REPLACE(Time, '.', '-')) > R.Date garantiza que solo se seleccionen eventos futuros (fechas posteriores a la fecha actual, R.Date).
  • Los eventos se ordenan en orden ascendente por hora (ORDER BY Time ASC), por lo que se selecciona la fecha del evento más próximo (LIMIT 1 garantiza que solo se devuelva una fecha).

Columnas en INFO_DATE:

  • E_ID: El ID del evento de UNIQUE_EVENTS.
  • Country: El país donde se celebra el evento.
  • Name: El nombre del evento.
  • Currency: La divisa del evento.
  • Next Event Date: La próxima fecha del evento, determinada por la subconsulta.

Consulta principal: Selección final y transformación

SELECT 
    E_ID as 'ID',
    Country,
    Name,
    Currency,
    (CASE WHEN "Next Event Date" IS NULL THEN 'Unknown' ELSE "Next Event Date" END) as 'Upcoming Date',
    (CASE WHEN "Next Event Date" <> 'Unknown' THEN 
        (CASE CAST (strftime('%w', DATE(REPLACE("Next Event Date", '.', '-'))) AS INTEGER)
            WHEN 0 THEN 'Sunday'
            WHEN 1 THEN 'Monday'
            WHEN 2 THEN 'Tuesday'
            WHEN 3 THEN 'Wednesday'
            WHEN 4 THEN 'Thursday'
            WHEN 5 THEN 'Friday'
            ELSE 'Saturday'
        END)  
    ELSE 'Unknown' END) as 'Day'
FROM INFO_DATE
ORDER BY "Upcoming Date" ASC;

La consulta principal recupera el resultado final del CTE INFO_DATE, transformando los resultados y añadiendo lógica adicional para gestionar los casos en los que puedan faltar fechas de eventos (valores NULL).

Columnas seleccionadas:

  • E_ID as 'ID': El ID del evento, renombrado como «ID».
  • Country: El país asociado al evento.
  • Name: El nombre del evento.
  • Currency: La divisa relacionada con el evento.
  • Upcoming Date: Esto se basa en la «Next Event Date». Si la «Next Event Date» es NULL, se mostrará «Unknown»; de lo contrario, se mostrará la fecha.

CASE WHEN "Next Event Date" IS NULL THEN 'Unknown' ELSE "Next Event Date" END

Esta instrucción CASE comprueba si hay una fecha válida para un evento próximo. Si la fecha es NULL, muestra «Unknown»; de lo contrario, muestra la «Next Event Date».

Cálculo del día de la semana:

  • Si la fecha del próximo evento no es «Unknown», la consulta convierte la fecha próxima en un día de la semana utilizando la siguiente instrucción CASE:

CASE CAST (strftime('%w', DATE(REPLACE("Next Event Date", '.', '-'))) AS INTEGER)
    WHEN 0 THEN 'Sunday'
    WHEN 1 THEN 'Monday'
    WHEN 2 THEN 'Tuesday'
    WHEN 3 THEN 'Wednesday'
    WHEN 4 THEN 'Thursday'
    WHEN 5 THEN 'Friday'
    ELSE 'Saturday'
END

La función strftime(“%w”, ...) extrae el día de la semana de la «Next Event Date»:

  • %w devuelve un número entero que representa el día de la semana (0 = Sunday, 1 = Monday, etc.).
  • La instrucción CASE asigna este número entero a un nombre de día (por ejemplo, 0 -> Sunday).
  • Si la fecha del próximo evento es «Unknown», la columna Day también mostrará «Unknown».

Ordenar los resultados:

ORDER BY "Upcoming Date" ASC;

Los resultados se ordenan por «Upcoming Date» en orden ascendente, lo que significa que los eventos más próximos aparecen primero.

Ejemplo de datos de salida de la vista «Upcoming Date»:

ID      	Country 	Name    						Currency	Upcoming Date		Day
410020004       South Korea     Industrial Production y/y       			KRW     	2024.09.30 01:00        Monday
410020005       South Korea     Retail Sales m/m        				KRW     	2024.09.30 01:00        Monday
410020006       South Korea     Index of Services m/m   				KRW     	2024.09.30 01:00        Monday
// ...
36500001        Australia       S&P Global Manufacturing PMI    			AUD     	2024.10.01 01:00        Tuesday
392030007       Japan   	Unemployment Rate       				JPY     	2024.10.01 01:30        Tuesday
392050002       Japan   	Jobs to Applicants Ratio        			JPY     	2024.10.01 01:30        Tuesday
// ...



Código del asesor experto

Este es el archivo principal del programa donde implementamos la estrategia de negociación de noticias. El código siguiente permite configurar los parámetros de entrada para operar con eventos de noticias personalizados.

input Choice iCustom_Event_1=No;//USE EVENT IDs BELOW?
input string iCustom_Event_1_IDs="";//EVENT IDs[Separate with a comma][MAX 14]
input Choice iCustom_Event_2=No;//USE EVENT IDs BELOW?
input string iCustom_Event_2_IDs="";//EVENT IDs[Separate with a comma][MAX 14]
input Choice iCustom_Event_3=No;//USE EVENT IDs BELOW?
input string iCustom_Event_3_IDs="";//EVENT IDs[Separate with a comma][MAX 14]
input Choice iCustom_Event_4=No;//USE EVENT IDs BELOW?
input string iCustom_Event_4_IDs="";//EVENT IDs[Separate with a comma][MAX 14]
input Choice iCustom_Event_5=No;//USE EVENT IDs BELOW?
input string iCustom_Event_5_IDs="";//EVENT IDs[Separate with a comma][MAX 14]

Explicación de cada entrada:

Choice iCustom_Event_1=No;

  • Tipo: Choice
  • Nombre de la variable: iCustom_Event_1
  • Valor predeterminado: No
  • Descripción: Esta entrada permite al usuario habilitar o deshabilitar el uso de ID de eventos personalizados para el evento 1. El tipo Choice aquí es un tipo enumerado con dos valores, Yes y No. Si se establece en Yes, el programa utilizará los ID de evento proporcionados en la entrada de cadena correspondiente (iCustom_Event_1_IDs).

string iCustom_Event_1_IDs="";

  • Tipo: string
  • Nombre de la variable: iCustom_Event_1_IDs
  • Valor predeterminado: An empty string ""
  • Descripción: Esta entrada permite al usuario introducir una lista de ID de eventos para el evento personalizado 1. Se espera que estos ID estén separados por comas (por ejemplo, «36010006,840030005,840030016») y se especifica un máximo de 14 ID.

 Inicialización de eventos de noticias personalizados

CEvent1.useEvents = Answer(iCustom_Event_1);
StringSplit(iCustom_Event_1_IDs, ',', CEvent1.EventIds);
CEvent2.useEvents = Answer(iCustom_Event_2);
StringSplit(iCustom_Event_2_IDs, ',', CEvent2.EventIds);
CEvent3.useEvents = Answer(iCustom_Event_3);
StringSplit(iCustom_Event_3_IDs, ',', CEvent3.EventIds);
CEvent4.useEvents = Answer(iCustom_Event_4);
StringSplit(iCustom_Event_4_IDs, ',', CEvent4.EventIds);
CEvent5.useEvents = Answer(iCustom_Event_5);
StringSplit(iCustom_Event_5_IDs, ',', CEvent5.EventIds);

Este bloque de código inicializa varios objetos de eventos de noticias personalizados (CEvent1, CEvent2, etc.) y procesa sus ID relacionados.

  • CEvent1.useEvents = Answer(iCustom_Event_1);:
    • CEvent1 es una estructura que contiene información sobre un conjunto específico de eventos de noticias personalizados. El indicador useEvents se establece mediante la función Answer(), que devuelve un valor booleano (verdadero o falso) basado en la variable de entrada iCustom_Event_1.
    • Si iCustom_Event_1 es verdadero, el experto utilizará este evento personalizado para la lógica de negociación; de lo contrario, lo ignorará.
  • StringSplit(iCustom_Event_1_IDs, ',', CEvent1.EventIds);:
    • StringSplit() es una función que divide una cadena de ID de eventos (iCustom_Event_1_IDs) mediante una coma (,), y la lista resultante de ID de eventos se almacena en CEvent1.EventIds.
    • iCustom_Event_1_IDs es una cadena que contiene uno o más ID de eventos, y la función split convierte esta cadena en una matriz de ID de eventos para su uso posterior en la lógica de negociación.

Código similar para CEvent2 a CEvent5.

Función OnInit()

Esta es la función de inicialización que se invoca cuando se inicia el EA o se añade a un gráfico.

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Assign if in LightMode or not
   isLightMode=(iDisplayMode==Display_LightMode)?true:false;
//--- call function for common initialization procedure
   InitCommon();
//--- store Init result
   int InitResult;
   if(!MQLInfoInteger(MQL_TESTER))//Checks whether the program is in the strategy tester
     {
      //--- initialization procedure outside strategy tester
      InitResult=InitNonTester();
     }
   else
     {
      //--- initialization procedure inside strategy tester
      InitResult=InitTester();
     }
//--- Create DB in memory
   NewsObject.CreateEconomicDatabaseMemory();
//--- Initialize Candle properties pointer object
   CP = new CCandleProperties();
//--- Retrieve news events for the current Daily period into array CalendarArray
   NewsObject.EconomicDetailsMemory(CalendarArray,CTM.Time(TimeTradeServer(),0,0,0),
                                    (iOrderType!=StopOrdersType)?true:false);
//--- Initialize Common graphics class pointer object
   CGraphics = new CCommonGraphics(Answer(iDisplay_Date),Answer(iDisplay_Spread),
                                   Answer(iDisplay_NewsInfo),Answer(iDisplay_EventObj));
   CGraphics.GraphicsRefresh(iSecondsPreEvent);//-- Create chart objects
//--- Set Time
   CDay.SetmyTime(CalendarArray);
   /* create timer, if in the strategy tester set the timer to 30s else 100ms */
   EventSetMillisecondTimer((!MQLInfoInteger(MQL_TESTER))?100:30000);
//-- Initialize Trade Management class pointer object
   Trade = new CTradeManagement(iDeviation);
//--- return Init result
   return InitResult;
  }

Pasos clave:

Modo de visualización:

  • La EA comprueba si se está ejecutando en modo claro o en modo oscuro (isLightMode).

Inicialización común:

  • Llama a la función InitCommon() para realizar tareas generales de inicialización.

Comprobación del Probador de estrategias:

  • Comprueba si el EA se está ejecutando en el modo de Probador de estrategias utilizando MQLInfoInteger(MQL_TESTER) y, a continuación, llama a InitNonTester() o InitTester() en función del resultado.

Base de datos de eventos de noticias:

  • La función NewsObject.CreateEconomicDatabaseMemory() inicializa la base de datos en memoria para eventos económicos. Aquí es donde el EA almacena los datos relacionados con las noticias.

Inicializar las propiedades de la vela:

  • Se crea el puntero de clase CP para CCandleProperties. Esta clase se encarga de gestionar las propiedades de las velas, como la apertura, el cierre, el máximo, el mínimo, etc.

Recuperar eventos de noticias:

  • La función NewsObject.EconomicDetailsMemory() recupera los eventos de noticias relevantes según los criterios seleccionados. Filtra las noticias relevantes para la jornada bursátil actual.

Inicializar objetos gráficos:

  • Se inicializa la clase CGraphics, que se encarga de crear elementos gráficos en el gráfico, como visualizar datos de eventos de noticias. El método GraphicsRefresh() garantiza que los objetos gráficos se actualicen según el tiempo configurado (iSecondsPreEvent).

Ajustar hora y temporizador:

  • El método CDay.SetmyTime() procesa la matriz de eventos de noticias y gestiona el tiempo para las operaciones bursátiles.
  • Se configura un temporizador con diferentes intervalos dependiendo de si el EA se está ejecutando en el modo de prueba o en el modo en vivo (EventSetMillisecondTimer()), con el fin de proporcionar rendimiento al probar el experto en el probador de estrategias.

Inicializar la gestión comercial:

  • El puntero de clase Trade se inicializa con iDeviation para abrir operaciones de orden stop si es necesario.

Resultado de inicialización Return:

  • La función devuelve el resultado del proceso de inicialización.

Función OnTimer

La función OnTimer() se activa periódicamente y se ejecuta cada vez que se llama a un evento del temporizador.

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
   if(((!MQLInfoInteger(MQL_TESTER))?int(TimeTradeServer())%30==0:true))
     {
      //--- Store start-up time.
      static datetime Startup_date = TimeTradeServer();
      if(CTM.DateisToday(Startup_date)&&CP.NewCandle(0,PERIOD_D1)
         &&MQLInfoInteger(MQL_TESTER))
        {
         //--- Retrieve news events for the current Daily period into array CalendarArray
         NewsObject.EconomicDetailsMemory(CalendarArray,CTM.Time(TimeTradeServer(),0,0,0),
                                          (iOrderType!=StopOrdersType)?true:false);
         //--- Initialize Common graphics class pointer object
         CGraphics = new CCommonGraphics(Answer(iDisplay_Date),Answer(iDisplay_Spread),
                                         Answer(iDisplay_NewsInfo),Answer(iDisplay_EventObj));
         CGraphics.GraphicsRefresh(iSecondsPreEvent);//-- Create chart objects
         //--- Set Time
         CDay.SetmyTime(CalendarArray);
        }
      //--- Run procedures
      ExecutionOnTimer(Startup_date);
      if(CTS.isSessionStart()&&!CTS.isSessionEnd())
        {
         //--- function to open trades
         TradeTime();
        }
      //--- close trades within 45 min before end of session
      if(CTS.isSessionStart()&&CTS.isSessionEnd()&&!CTS.isSessionEnd(0,0))
        {
         Trade.CloseTrades("NewsTrading");
        }
     }
  }

Características principales:

  • Condiciones basadas en el tiempo: la instrucción «if» comprueba si el código se está ejecutando en el probador de estrategias o en tiempo real. Si se ejecuta en tiempo real (fuera del probador de estrategias), comprueba si la hora del servidor es divisible por 30 (para un intervalo de 30 segundos).
  • Actualización sobre velas y noticias:
    • Si la fecha de hoy coincide con la fecha de inicio. Si hoy es un nuevo día y se ha formado una nueva vela diaria (CP.NewCandle(0, PERIOD_D1)), el experto obtiene las noticias económicas del día actual utilizando NewsObject.EconomicDetailsMemory.
    • También actualiza el gráfico con nueva información.
  • Control de sesión: Si la sesión de negociación ha comenzado (CTS.isSessionStart()), se permitirán operaciones durante la sesión. El experto también cerrará las operaciones si la sesión está a punto de terminar.

Función ExecutionOnTimer

//+------------------------------------------------------------------+
//|Execute program procedures in time intervals                      |
//+------------------------------------------------------------------+
void ExecutionOnTimer(datetime Startup_date)
  {
//--- Check if not start-up date
   if(!CTM.DateisToday(Startup_date))
     {
      //--- Run every New Daily Candle
      if(CP.NewCandle(1,PERIOD_D1))
        {
         //--- Check if not in strategy tester
         if(!MQLInfoInteger(MQL_TESTER))
           {
            //--- Update/Create DB in Memory
            NewsObject.CreateEconomicDatabaseMemory();
           }
         //--- retrieve news events for the current day
         NewsObject.EconomicDetailsMemory(CalendarArray,CTM.Time(TimeTradeServer(),0,0,0),
                                          (iOrderType!=StopOrdersType)?true:false);
         //--- Set time from news events
         CDay.SetmyTime(CalendarArray);
         CGraphics.GraphicsRefresh(iSecondsPreEvent);//-- Create/Re-create chart objects
        }
      //--- Check if not in strategy tester
      if(!MQLInfoInteger(MQL_TESTER))
        {
         //--- Run every New Hourly Candle
         if(CP.NewCandle(2,PERIOD_H1))
           {
            //--- Check if DB in Storage needs an update
            if(NewsObject.UpdateRecords())
              {
               //--- initialization procedure outside strategy tester
               InitNonTester();
              }
           }
        }
     }
   else
     {
      //--- Run every New Daily Candle
      if(CP.NewCandle(3,PERIOD_D1))
        {
         //--- Update Event objects on chart
         CGraphics.NewsEvent();
        }
     }
//--- Update realtime Graphic every 1 min
   if(CP.NewCandle(4,PERIOD_M1))
     {
      //--- get the news events for the next min ahead of time.
      datetime Time_ahead = TimeTradeServer()+CTM.MinutesS();
      CDay.GetmyTime(CTV.Hourly(CTM.ReturnHour(Time_ahead)),
                     CTV.Minutely(CTV.Minutely(CTM.ReturnMinute(Time_ahead))),
                     myTimeData,myEvents);
      CGraphics.Block_2_Realtime(iSecondsPreEvent);
     }
  }

Características principales:

  • Actualización diaria de velas: Comprueba si hay nuevas velas diarias. Si se ha formado una nueva vela diaria, se actualiza la base de datos de noticias (NewsObject.CreateEconomicDatabaseMemory()) y se recuperan los eventos noticiosos del día.
  • Actualización de velas por hora: Si se forma una nueva vela por hora, el EA comprueba si la base de datos de noticias económicas requiere una actualización y, en caso afirmativo, reinicia el EA fuera del modo de prueba de estrategias (InitNonTester()).
  • Actualizaciones en tiempo real: Cada minuto, el EA actualiza los gráficos en tiempo real en el gráfico y recupera las noticias del minuto siguiente, preparándose para las operaciones en consecuencia.

Función TradeTime

Esta función gestiona la ejecución de operaciones en torno a acontecimientos de noticias.

//+------------------------------------------------------------------+
//|function to check trading time                                    |
//+------------------------------------------------------------------+
void TradeTime()
  {
//--- Iterate through the event times
   for(uint i=0;i<myTimeData.Size();i++)
     {
      //--- Check if it is time to trade each news event
      if(CTM.TimePreEvent(CTM.TimeMinusOffset(datetime(myEvents[i].EventDate),iSecondsPreEvent)
                          ,datetime(myEvents[i].EventDate))
         &&(CTM.isDayOfTheWeek(TradingDay)||iNewSelection==News_Select_Custom_Events))
        {
         //--- switch for order type selection
         switch(iOrderType)
           {
            case StopOrdersType:// triggers for STOP ORDERS
               StopOrders(myEvents[i]);
               break;
            default:// triggers for both MARKET POSITION & SINGLE STOP ORDER
               SingleOrder(myEvents[i]);
               break;
           }
        }
     }
  }

Características principales:

  • Comprobación de la hora del evento: Para cada evento de la matriz myTimeData, el EA comprueba si la hora actual se encuentra dentro de la ventana de tiempo «previa al evento» predefinida (iSecondsPreEvent) antes del evento real.
  • Filtro de día de la semana: Las operaciones solo se abren si el día actual coincide con el día de negociación configurado (TradingDay) o si se seleccionan eventos personalizados (iNewSelection == News_Select_Custom_Events).
  • Selección del tipo de orden: Según la entrada iOrderType (posición de mercado u orden(es) stop), la función abre órdenes de mercado u órdenes stop en torno al evento noticioso.

Función SingleOrder

Esta función abre órdenes de mercado único u órdenes stop en función del impacto de la noticia.

//+------------------------------------------------------------------+
//|function to open single order types                               |
//+------------------------------------------------------------------+
void SingleOrder(Calendar &NewsEvent)
  {
//--- Check each Impact value type
   switch(NewsObject.IMPACT(NewsEvent.EventImpact))
     {
      //--- When Impact news is negative
      case CALENDAR_IMPACT_NEGATIVE:
         //--- Check if profit currency is news event currency
         if(NewsEvent.EventCurrency==CSymbol.CurrencyProfit())
           {
            switch(iOrderType)
              {
               case  MarketPositionType:// triggers for MARKET POSITION
                  //--- Open buy trade with Event id as Magic number
                  Trade.Buy(iStoploss,iTakeprofit,ulong(NewsEvent.EventId),
                            "NewsTrading-"+NewsEvent.EventCode);
                  break;
               case StopOrderType:// triggers for SINGLE STOP ORDER
                  //--- Open buy-stop with Event id as Magic number
                  Trade.OpenBuyStop(iStoploss,iTakeprofit,ulong(NewsEvent.EventId),
                                    "NewsTrading-SStop-"+NewsEvent.EventCode);
                  break;
               default:
                  break;
              }
           }
         else
           {
            switch(iOrderType)
              {
               case  MarketPositionType:// triggers for MARKET POSITION
                  //--- Open sell trade with Event id as Magic number
                  Trade.Sell(iStoploss,iTakeprofit,ulong(NewsEvent.EventId),
                             "NewsTrading-"+NewsEvent.EventCode);
                  break;
               case StopOrderType:// triggers for SINGLE STOP ORDER
                  //--- Open buy-stop with Event id as Magic number
                  Trade.OpenSellStop(iStoploss,iTakeprofit,ulong(NewsEvent.EventId),
                                     "NewsTrading-SStop-"+NewsEvent.EventCode);
                  break;
               default:
                  break;
              }
           }
         break;
      //--- When Impact news is positive
      case CALENDAR_IMPACT_POSITIVE:
         //--- Check if profit currency is news event currency
         if(NewsEvent.EventCurrency==CSymbol.CurrencyProfit())
           {
            switch(iOrderType)
              {
               case  MarketPositionType:// triggers for MARKET POSITION
                  //--- Open sell trade with Event id as Magic number
                  Trade.Sell(iStoploss,iTakeprofit,ulong(NewsEvent.EventId),
                             "NewsTrading-"+NewsEvent.EventCode);
                  break;
               case StopOrderType:// triggers for SINGLE STOP ORDER
                  //--- Open sell-stop with Event id as Magic number
                  Trade.OpenSellStop(iStoploss,iTakeprofit,ulong(NewsEvent.EventId),
                                     "NewsTrading-SStop-"+NewsEvent.EventCode);
                  break;
               default:
                  break;
              }

           }
         else
           {
            switch(iOrderType)
              {
               case  MarketPositionType:// triggers for MARKET POSITION
                  //--- Open buy trade with Event id as Magic number
                  Trade.Buy(iStoploss,iTakeprofit,ulong(NewsEvent.EventId),
                            "NewsTrading-"+NewsEvent.EventCode);
                  break;
               case StopOrderType:// triggers for SINGLE STOP ORDER
                  //--- Open sell-stop with Event id as Magic number
                  Trade.OpenBuyStop(iStoploss,iTakeprofit,ulong(NewsEvent.EventId),
                                    "NewsTrading-SStop-"+NewsEvent.EventCode);
                  break;
               default:
                  break;
              }
           }
         break;
      //--- Unknown
      default:
         break;
     }
  }

Características principales:

  • Evaluación del impacto: El EA evalúa el impacto del evento noticioso (NewsObject.IMPACT(NewsEvent.EventImpact)), que puede ser negativo o positivo.
    • Impacto negativo: Si el impacto de la noticia es negativo y la divisa del evento coincide con la divisa de beneficio de la cuenta, se abre una operación de compra si el iOrderType es una posición de mercado o una orden de compra stop para órdenes stop. Si la divisa del evento no coincide con la divisa de la ganancia, se abre una operación de venta o una orden de venta stop.
    • Impacto positivo: Si el impacto de la noticia es positivo y la divisa del evento coincide con la divisa de la ganancia, se abre una operación de venta o una orden de venta stop. Si la divisa del evento no coincide, se abre una orden de compra o una orden stop de compra.

Función StopOrders

Esta función gestiona la apertura simultánea de órdenes stop de compra y stop de venta en torno al evento de noticias. Independientemente del impacto del evento, ambos tipos de órdenes stop se colocan para capturar los movimientos de precios en cualquier dirección.

//+------------------------------------------------------------------+
//|function to open orders                                           |
//+------------------------------------------------------------------+
void StopOrders(Calendar &NewsEvent)
  {
//--- Opens both buy-stop & sell-stop regardless of event impact
   Trade.OpenStops(iStoploss,iTakeprofit,ulong(NewsEvent.EventId),
                   "NewsTrading-Stops-"+NewsEvent.EventCode);
  }

Características principales:

  • Órdenes de compra y venta con límite: Abre ambos tipos de órdenes con límite, cada una vinculada a un evento específico con el EventId del evento utilizado como número mágico de la operación.

Función OnTrade

Esta función se activa cada vez que se produce un nuevo evento comercial. Esta función se utilizará para gestionar las operaciones.

void OnTrade()
{
   //--- Check if time is within the trading session
   if(CTS.isSessionStart() && !CTS.isSessionEnd(0,0))
   {
      //--- Run procedures
      ExecutionOnTrade();
   }
}

  • CTS.isSessionStart() and !CTS.isSessionEnd(0,0):
    • CTS (objeto de clase de sesiones) se utiliza para comprobar si la hora actual se encuentra dentro de una sesión bursátil activa.
    • isSessionStart() comprueba si la sesión ha comenzado.
    • !CTS.isSessionEnd(0,0) comprueba si la sesión aún no ha finalizado. Los argumentos 0,0 representan el desfase o periodo de amortiguación antes de que finalice la sesión.
    • Esto garantiza que las operaciones solo se ajusten si la hora actual se encuentra dentro de una sesión de negociación activa.
  • ExecutionOnTrade();:
    • Si la sesión está activa, se llama a la función ExecutionOnTrade() para gestionar la ejecución de los procedimientos necesarios relacionados con la nueva operación.

Función ExecutionOnTrade

Esta función contiene la lógica que se ejecuta cada vez que se realiza una nueva operación.

void ExecutionOnTrade()
{
   //--- if stop orders, enable fundamental mode
   if(iOrderType == StopOrdersType)
   {
      Trade.FundamentalMode("NewsTrading");
   }
   
   //--- when stop order(s), enable slippage reduction
   if(iOrderType != MarketPositionType)
   {
      Trade.SlippageReduction(iStoploss, iTakeprofit, "NewsTrading");
   }
}

  • if (iOrderType == StopOrdersType):
    • Esto comprueba si la operación actual es una orden stop (StopOrdersType). Si la condición es verdadera, el código llama a la función Trade.FundamentalMode().
  • Trade.FundamentalMode("NewsTrading");:
    • Esta función habilita el modo fundamental, que se encarga de eliminar las órdenes pendientes en la dirección opuesta.
    • "NewsTrading": Esta es la etiqueta comercial/comentario para el EA.
  • if(iOrderType != MarketPositionType):
    • Esta condición comprueba si la variable de entrada no es la enumeración MarketPositionType. Si es cierto, el código permite reducir el deslizamiento.
  • Trade.SlippageReduction(iStoploss, iTakeprofit, "NewsTrading"):
    • Esta función reduce el deslizamiento para las órdenes no de mercado.
    • El deslizamiento se produce cuando el precio ejecutado difiere del precio esperado, especialmente durante mercados volátiles o acontecimientos de noticias.
    • Al llamar a SlippageReduction(), el EA intenta minimizar este deslizamiento.
    • Parámetros:
      • iStoploss: El valor de stop-loss, que es el precio al que la operación debe cerrarse automáticamente para limitar las pérdidas potenciales.
      • iTakeprofit: El valor de take-profit, que es el precio al que la operación debe cerrarse automáticamente para asegurar las ganancias.
      • "NewsTrading": Esta es la etiqueta comercial/comentario para el EA.


Conclusión

En este artículo, el experto permite a los usuarios definir eventos de noticias personalizados con los que operará el asesor experto. Estos eventos se inicializan utilizando las entradas del usuario, que luego son analizadas y gestionadas por el experto. Se mejoró la base de datos del calendario almacenada para proporcionar información adicional sobre los próximos eventos y los eventos recientes en forma de vistas, y se explicó detalladamente la consulta de cada vista. Se añadieron las funciones OnTimer y OnTrade para controlar la ejecución del código en función de condiciones de tiempo específicas. Gracias por tu tiempo, espero poder ofrecerte más información interesante en el próximo artículo. :) 

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

Archivos adjuntos |
Hamid Rabia
Hamid Rabia | 10 ene 2025 en 12:28
¡¡Muy buen artículo!!
entropie
entropie | 25 abr 2025 en 14:01
Hola, ¿es posible añadir automáticamente un trailing stop a cada operación que abro mediante un script o algo similar?
Desarrollo de asesores expertos autooptimizables en MQL5 (Parte 3): Estrategias dinámicas de seguimiento de tendencias y reversión a la media Desarrollo de asesores expertos autooptimizables en MQL5 (Parte 3): Estrategias dinámicas de seguimiento de tendencias y reversión a la media
Los mercados financieros suelen clasificarse en dos tipos: los que se mueven dentro de un rango y los que siguen una tendencia. Esta visión estática del mercado puede facilitarnos las operaciones a corto plazo. Sin embargo, está desconectado de la realidad del mercado. En este artículo, buscamos comprender mejor cómo se mueven exactamente los mercados financieros entre estos dos modos posibles y cómo podemos utilizar nuestra nueva comprensión del comportamiento del mercado para ganar confianza en nuestras estrategias de negociación algorítmica.
Reimaginando las estrategias clásicas en MQL5 (Parte 13): Minimizar el retraso en los cruces de medias móviles Reimaginando las estrategias clásicas en MQL5 (Parte 13): Minimizar el retraso en los cruces de medias móviles
Los cruces de medias móviles son ampliamente conocidos por los operadores de nuestra comunidad y, sin embargo, la esencia de la estrategia ha cambiado muy poco desde su creación. En este artículo, le presentaremos un ligero ajuste a la estrategia original, cuyo objetivo es minimizar el retraso presente en la estrategia de trading. Todos los seguidores de la estrategia original podrían considerar revisar la estrategia de acuerdo con las ideas que discutiremos hoy. Al utilizar dos medias móviles con el mismo periodo, reducimos considerablemente el retraso en la estrategia de trading, sin violar los principios fundamentales de la estrategia.
Métodos de conjunto para mejorar las tareas de clasificación en MQL5 Métodos de conjunto para mejorar las tareas de clasificación en MQL5
En este artículo, presentamos la implementación de varios clasificadores de conjunto en MQL5 y analizamos su eficacia en diferentes situaciones.
Automatización de estrategias de trading en MQL5 (Parte 3): Sistema RSI de recuperación de zona para la gestión dinámica de operaciones Automatización de estrategias de trading en MQL5 (Parte 3): Sistema RSI de recuperación de zona para la gestión dinámica de operaciones
En este artículo, creamos un sistema (un EA) de recuperación de zona RSI en MQL5, utilizando señales RSI para lanzar operaciones y una estrategia de recuperación para gestionar las pérdidas. Implementamos una clase «ZoneRecovery» para automatizar las entradas de operaciones, la lógica de recuperación y la gestión de posiciones. El artículo concluye con información sobre backtesting para optimizar el rendimiento y mejorar la eficacia del EA.