English Русский 中文 Deutsch 日本語 Português
preview
Recetas MQL5 - Base de datos de eventos macroeconómicos

Recetas MQL5 - Base de datos de eventos macroeconómicos

MetaTrader 5Ejemplos | 10 mayo 2023, 13:09
428 0
Denis Kirichenko
Denis Kirichenko

Introducción

Este artículo se centrará en cómo agrupar y gestionar los datos que describen los eventos del calendario macroeconómico.

En el mundo actual, con flujos de información constantes y omnipresentes, a la hora de analizar los eventos hay que tratar con big data. Aunque el artículo se centrará más en la forma que en el contenido, parece que la correcta organización y estructuración de los datos contribuye en gran medida a convertirlos en información.

Para resolver estos problemas, usaremos SQLite. Tenga en cuenta que el desarrollador ha añadido soporte para trabajar con bases de datos SQLite directamente desde MQL5 en el build 2265 (6 de diciembre de 2019). Antes había que utilizar diferentes conectores, como el descrito en SQL y MQL5: Trabajando con una base de datos SQLite.


1. Documentación y material adicional

Un breve recorrido por la Documentación en relación con el trabajo con bases de datos. El desarrollador ofrece 26 funciones nativas:

  1. DatabaseOpen();
  2. DatabaseClose();
  3. DatabaseImport();
  4. DatabaseExport();
  5. DatabasePrint();
  6. DatabaseTableExists();
  7. DatabaseExecute();
  8. DatabasePrepare();
  9. DatabaseReset();
  10. DatabaseBind();
  11. DatabaseBindArray();
  12. DatabaseRead();
  13. DatabaseReadBind();
  14. DatabaseFinalize();
  15. DatabaseTransactionBegin();
  16. DatabaseTransactionCommit();
  17. DatabaseTransactionRollback();
  18. DatabaseColumnsCount();
  19. DatabaseColumnName();
  20. DatabaseColumnType();
  21. DatabaseColumnSize();
  22. DatabaseColumnText();
  23. DatabaseColumnInteger();
  24. DatabaseColumnLong();
  25. DatabaseColumnDouble();
  26. DatabaseColumnBlob().

También hay un bloque estadístico y otro de funciones matemáticas añadidos más recientemente. Y, por supuesto, el punto de partida para aprender esta funcionalidad será SQLite: trabajo nativo con bases de datos en SQL en MQL5


2. Clase CDatabase

Para facilitar el trabajo con las bases de datos, crearemos una clase CDatabase. Vamos a describir primero la composición de la clase. A continuación, utilizaremos ejemplos para comprobar cómo funciona.

Los miembros de datos de la clase CDatabase son los siguientes:

  • m_name - nombre del archivo de la base de datos (con extensión);
  • m_handle - manejador de la base de datos;
  • m_flags - combinación de banderas;
  • m_table_names - nombres de las tablas;
  • m_curr_table_name - nombre de la tabla actual;
  • m_sql_request_ha - manejador de la última consulta SQL;
  • m_sql_request - última consulta SQL.

En cuanto a los métodos, podemos dividirlos en varios grupos:

  1. Métodos que incorporan funciones nativas para trabajar con las bases de datos (funciones API MQL5);
  2. Métodos para trabajar con tablas;
  3. Métodos para trabajar con consultas;
  4. Métodos para trabajar con vistas;
  5. Métodos para recuperar los valores de los miembros de datos (get-methods).

Querríamos hacer la siguiente observación. En SQLite hay multitud de formularios de consultas, desde sencillos a complejos. La intención no era crear un método personalizado en la clase CDatabase para cada formulario de esta clase.  Si no existe un método para realizar una consulta concreta en la clase, la consulta podrá generarse utilizando el método universal CDatabase::Select().

 

Veamos ahora algunos ejemplos sobre cómo utilizar las funciones de CDatabase.


2.1 Creando una base de datos

Crearemos nuestra primera base de datos de calendarios usando el script 1_create_calendar_db.mq5.  En el script solo habrá unas pocas líneas de código.

//--- include
#include "..\CDatabase.mqh"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   CDatabase db_obj;
   string file_name="Databases\\test_calendar_db.sqlite";
   uint flags=DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE;
   if(!db_obj.Open(file_name, flags))
      ::PrintFormat("Failed to create a calendar database \"%s\"!", file_name);
   db_obj.Close();
  }
//+------------------------------------------------------------------+

Después de ejecutar el script, veremos que el archivo de base de datos test_calendar_db.sqlite aparece en la carpeta %MQL5\Files\Databases (Fig.1).


Archivo de base de datos test_calendar_db.sqlite

Fig.1 Archivo de base de datos test_calendar_db.sqlite


Si además abrimos este archivo en el editor de código, veremos que la base de datos está vacía (Fig.2).


Base de datos Test_calendar_db

Fig.2 Base de datos test_calendar_db


2.2 Creando una tabla

Vamos a intentar rellenar la base de datos. Para ello, crearemos una tabla llamada COUNTRIES en la que enumeraremos los países cuyos eventos de calendario serán tratados posteriormente por nuestras consultas. De esto se encargará el script 2_create_countries_table.mq5.

//--- include
#include "..\CDatabase.mqh"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
   {
//--- open a database
   CDatabase db_obj;
   string file_name="Databases\\test_calendar_db.sqlite";
   uint flags=DATABASE_OPEN_READWRITE;
   if(!db_obj.Open(file_name, flags))
      {
      ::PrintFormat("Failed to open a calendar database \"%s\"!", file_name);
      db_obj.Close();
      return;
      }
//--- create a table
   string table_name="COUNTRIES";
   string params[]=
      {
      "COUNTRY_ID UNSIGNED BIG INT PRIMARY KEY NOT NULL,", // 1) country ID
      "NAME TEXT,"                                         // 2) country name
      "CODE TEXT,"                                         // 3) country code
      "CONTINENT TEXT,"                                    // 4) country continent
      "CURRENCY TEXT,"                                     // 5) currency code
      "CURRENCY_SYMBOL TEXT,"                              // 6) currency symbol
      "URL_NAME TEXT"                                      // 7) country URL
      };
   if(!db_obj.CreateTable(table_name, params))
      {
      ::PrintFormat("Failed to create a table \"%s\"!", table_name);
      db_obj.Close();
      return;
      }
   db_obj.Close();
   }
//+------------------------------------------------------------------+

Tras ejecutar el script, veremos que la tabla COUNTRIES aparece en la base de datos (Figura 3).


Tabla COUNTRIES vacía

Figura 3 Tabla COUNTRIES vacía


2.3 Rellenando la tabla

Vamos a rellenar la nueva tabla con datos. Para ello, utilizaremos las funciones de la clase CiCalendarInfo. Podrá leer más información sobre la clase en el artículo "Recetas MQL5 – Calendario económico". La tarea en sí será realizada por el script 3_fill_in_countries_table.mq5.

//--- include
#include "..\CalendarInfo.mqh"
#include "..\CDatabase.mqh"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
   {
//--- open a database
   CDatabase db_obj;
   string file_name="Databases\\test_calendar_db.sqlite";
   uint flags=DATABASE_OPEN_READWRITE;
   if(!db_obj.Open(file_name, flags))
      {
      db_obj.Close();
      return;
      }
//--- open a table
   string table_name="COUNTRIES";
   if(db_obj.SelectTable(table_name))
      if(db_obj.EmptyTable())
         {
         db_obj.FinalizeSqlRequest();
         string col_names[]=
            {
            "COUNTRY_ID", "NAME", "CODE", "CONTINENT",
            "CURRENCY", "CURRENCY_SYMBOL", "URL_NAME"
            };
//--- fill in the table
         CiCalendarInfo calendar_info;
         if(calendar_info.Init())
            {
            MqlCalendarCountry calendar_countries[];
            if(calendar_info.GetCountries(calendar_countries))
               {
               if(db_obj.TransactionBegin())
                  for(int c_idx=0; c_idx<::ArraySize(calendar_countries); c_idx++)
                     {
                     MqlCalendarCountry curr_country=calendar_countries[c_idx];
                     string col_vals[];
                     ::ArrayResize(col_vals, 7);
                     col_vals[0]=::StringFormat("%I64u", curr_country.id);
                     col_vals[1]=::StringFormat("'%s'", curr_country.name);
                     col_vals[2]=::StringFormat("'%s'", curr_country.code);
                     col_vals[3]="NULL";
                     SCountryByContinent curr_country_continent_data;
                     if(curr_country_continent_data.Init(curr_country.code))
                        col_vals[3]=::StringFormat("'%s'",
                                                   curr_country_continent_data.ContinentDescription());
                     col_vals[4]=::StringFormat("'%s'", curr_country.currency);
                     col_vals[5]=::StringFormat("'%s'", curr_country.currency_symbol);
                     col_vals[6]=::StringFormat("'%s'", curr_country.url_name);
                     if(!db_obj.InsertSingleRow(col_names, col_vals))
                        {
                        db_obj.TransactionRollback();
                        db_obj.Close();
                        return;
                        }
                     db_obj.FinalizeSqlRequest();
                     }
               if(!db_obj.TransactionCommit())
                  ::PrintFormat("Failed to complete transaction execution, error %d", ::GetLastError());
               }
            //--- print
            if(db_obj.PrintTable()<0)
               ::PrintFormat("Failed to print the table \"%s\", error %d", table_name, ::GetLastError());
            }
         }
   db_obj.Close();
   }
//+------------------------------------------------------------------+

Imprimiremos los datos de la tabla COUNTRIES en el diario de registro.

3_fill_in_countries_table (EURUSD,H1)    #| COUNTRY_ID NAME           CODE CONTINENT         CURRENCY CURRENCY_SYMBOL URL_NAME      
3_fill_in_countries_table (EURUSD,H1)   --+-----------------------------------------------------------------------------------------
3_fill_in_countries_table (EURUSD,H1)    1|        554 New Zealand    NZ   Australia/Oceania NZD      $               new-zealand    
3_fill_in_countries_table (EURUSD,H1)    2|        999 European Union EU   Europe            EUR      €               european-union 
3_fill_in_countries_table (EURUSD,H1)    3|        392 Japan          JP   Asia              JPY      ¥               japan          
3_fill_in_countries_table (EURUSD,H1)    4|        124 Canada         CA   North America     CAD      $               canada         
3_fill_in_countries_table (EURUSD,H1)    5|         36 Australia      AU   Australia/Oceania AUD      $               australia      
3_fill_in_countries_table (EURUSD,H1)    6|        156 China          CN   Asia              CNY      ¥               china          
3_fill_in_countries_table (EURUSD,H1)    7|        380 Italy          IT   Europe            EUR      €               italy          
3_fill_in_countries_table (EURUSD,H1)    8|        702 Singapore      SG   Asia              SGD      R$              singapore      
3_fill_in_countries_table (EURUSD,H1)    9|        276 Germany        DE   Europe            EUR      €               germany        
3_fill_in_countries_table (EURUSD,H1)   10|        250 France         FR   Europe            EUR      €               france         
3_fill_in_countries_table (EURUSD,H1)   11|         76 Brazil         BR   South America     BRL      R$              brazil         
3_fill_in_countries_table (EURUSD,H1)   12|        484 Mexico         MX   North America     MXN      Mex$            mexico         
3_fill_in_countries_table (EURUSD,H1)   13|        710 South Africa   ZA   Africa            ZAR      R               south-africa   
3_fill_in_countries_table (EURUSD,H1)   14|        344 Hong Kong      HK   Asia              HKD      HK$             hong-kong      
3_fill_in_countries_table (EURUSD,H1)   15|        356 India          IN   Asia              INR      ₹               india          
3_fill_in_countries_table (EURUSD,H1)   16|        578 Norway         NO   Europe            NOK      Kr              norway         
3_fill_in_countries_table (EURUSD,H1)   17|        840 United States  US   North America     USD      $               united-states  
3_fill_in_countries_table (EURUSD,H1)   18|        826 United Kingdom GB   Europe            GBP      £               united-kingdom 
3_fill_in_countries_table (EURUSD,H1)   19|        756 Switzerland    CH   Europe            CHF      ₣               switzerland    
3_fill_in_countries_table (EURUSD,H1)   20|        410 South Korea    KR   Asia              KRW      ₩               south-korea    
3_fill_in_countries_table (EURUSD,H1)   21|        724 Spain          ES   Europe            EUR      €               spain          
3_fill_in_countries_table (EURUSD,H1)   22|        752 Sweden         SE   Europe            SEK      Kr              sweden         
3_fill_in_countries_table (EURUSD,H1)   23|          0 Worldwide      WW   World             ALL                      worldwide      


En el MetaEditor la tabla tendrá el siguiente aspecto (Fig.4).

Tabla COUNTRIES rellenadas

Figura 4 Tabla COUNTRIES rellenadas



2.4 Seleccionando algunas columnas de la tabla

Vamos a trabajar con los datos de la tabla COUNTRIES. Supongamos que debemos seleccionar estas columnas:

  • "COUNTRY_ID";
  • "COUNTRY_NAME";
  • "COUNTRY_CODE";
  • "COUNTRY_CONTINENT";
  • "CURRENCY".

Crearemos la consulta SQL utilizando el script 4_select_some_columns.mq5 como sigue:

//--- include
#include "..\CDatabase.mqh"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
   {
//--- open a database
   CDatabase db_obj;
   string file_name="Databases\\test_calendar_db.sqlite";
   uint flags=DATABASE_OPEN_READONLY;
   if(!db_obj.Open(file_name, flags))
      {
      db_obj.Close();
      return;
      }
//--- check a table
   string table_name="COUNTRIES";
   if(db_obj.SelectTable(table_name))
      {
      string col_names_to_select[]=
         {
         "COUNTRY_ID", "NAME", "CODE",
         "CONTINENT", "CURRENCY"
         };
      if(!db_obj.SelectFrom(col_names_to_select))
         {
         db_obj.Close();
         return;
         }
      //--- print the SQL request
      if(db_obj.PrintSqlRequest()<0)
         ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError());
      db_obj.FinalizeSqlRequest();
      }
   db_obj.Close();
   }
//+------------------------------------------------------------------+


Al imprimir la consulta obtendremos:

4_select_some_columns (EURUSD,H1)        #| COUNTRY_ID NAME           CODE CONTINENT         CURRENCY
4_select_some_columns (EURUSD,H1)       --+----------------------------------------------------------
4_select_some_columns (EURUSD,H1)        1|        554 New Zealand    NZ   Australia/Oceania NZD      
4_select_some_columns (EURUSD,H1)        2|        999 European Union EU   Europe            EUR      
4_select_some_columns (EURUSD,H1)        3|        392 Japan          JP   Asia              JPY      
4_select_some_columns (EURUSD,H1)        4|        124 Canada         CA   North America     CAD      
4_select_some_columns (EURUSD,H1)        5|         36 Australia      AU   Australia/Oceania AUD      
4_select_some_columns (EURUSD,H1)        6|        156 China          CN   Asia              CNY      
4_select_some_columns (EURUSD,H1)        7|        380 Italy          IT   Europe            EUR      
4_select_some_columns (EURUSD,H1)        8|        702 Singapore      SG   Asia              SGD      
4_select_some_columns (EURUSD,H1)        9|        276 Germany        DE   Europe            EUR      
4_select_some_columns (EURUSD,H1)       10|        250 France         FR   Europe            EUR      
4_select_some_columns (EURUSD,H1)       11|         76 Brazil         BR   South America     BRL      
4_select_some_columns (EURUSD,H1)       12|        484 Mexico         MX   North America     MXN      
4_select_some_columns (EURUSD,H1)       13|        710 South Africa   ZA   Africa            ZAR      
4_select_some_columns (EURUSD,H1)       14|        344 Hong Kong      HK   Asia              HKD      
4_select_some_columns (EURUSD,H1)       15|        356 India          IN   Asia              INR      
4_select_some_columns (EURUSD,H1)       16|        578 Norway         NO   Europe            NOK      
4_select_some_columns (EURUSD,H1)       17|        840 United States  US   North America     USD      
4_select_some_columns (EURUSD,H1)       18|        826 United Kingdom GB   Europe            GBP      
4_select_some_columns (EURUSD,H1)       19|        756 Switzerland    CH   Europe            CHF      
4_select_some_columns (EURUSD,H1)       20|        410 South Korea    KR   Asia              KRW      
4_select_some_columns (EURUSD,H1)       21|        724 Spain          ES   Europe            EUR      
4_select_some_columns (EURUSD,H1)       22|        752 Sweden         SE   Europe            SEK      
4_select_some_columns (EURUSD,H1)       23|          0 Worldwide      WW   World             ALL      

Obviamente, el muestreo se ha realizado sin ningún tipo de clasificación.


2.5 Seleccionando algunas columnas clasificadas en la tabla

Intentaremos clasificar los datos de la tabla según la columna "COUNTRY_ID". Esta consulta tiene la siguiente implementación en el script 5_select_some_sorted_columns.mq5:

//--- include
#include "..\CDatabase.mqh"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
   {
//--- open a database
   CDatabase db_obj;
   string file_name="Databases\\test_calendar_db.sqlite";
   uint flags=DATABASE_OPEN_READONLY;
   if(!db_obj.Open(file_name, flags))
      {
      db_obj.Close();
      return;
      }
//--- check a table
   string table_name="COUNTRIES";
   if(db_obj.SelectTable(table_name))
      {
      string col_names_to_select[]=
         {
         "COUNTRY_ID", "NAME", "CODE",
         "CONTINENT", "CURRENCY"
         };
      string ord_names[1];
      ord_names[0]=col_names_to_select[0];
      if(!db_obj.SelectFromOrderedBy(col_names_to_select, ord_names))
         {
         db_obj.Close();
         return;
         }
      //--- print the SQL request
      if(db_obj.PrintSqlRequest()<0)
         ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError());
      db_obj.FinalizeSqlRequest();
      }
   db_obj.Close();
   }
//+------------------------------------------------------------------+


El resultado de la consulta aparecerá en el diario de registro:

5_select_some_sorted_columns (EURUSD,H1)         #| COUNTRY_ID NAME           CODE CONTINENT         CURRENCY
5_select_some_sorted_columns (EURUSD,H1)        --+----------------------------------------------------------
5_select_some_sorted_columns (EURUSD,H1)         1|          0 Worldwide      WW   World             ALL      
5_select_some_sorted_columns (EURUSD,H1)         2|         36 Australia      AU   Australia/Oceania AUD      
5_select_some_sorted_columns (EURUSD,H1)         3|         76 Brazil         BR   South America     BRL      
5_select_some_sorted_columns (EURUSD,H1)         4|        124 Canada         CA   North America     CAD      
5_select_some_sorted_columns (EURUSD,H1)         5|        156 China          CN   Asia              CNY      
5_select_some_sorted_columns (EURUSD,H1)         6|        250 France         FR   Europe            EUR      
5_select_some_sorted_columns (EURUSD,H1)         7|        276 Germany        DE   Europe            EUR      
5_select_some_sorted_columns (EURUSD,H1)         8|        344 Hong Kong      HK   Asia              HKD      
5_select_some_sorted_columns (EURUSD,H1)         9|        356 India          IN   Asia              INR      
5_select_some_sorted_columns (EURUSD,H1)        10|        380 Italy          IT   Europe            EUR      
5_select_some_sorted_columns (EURUSD,H1)        11|        392 Japan          JP   Asia              JPY      
5_select_some_sorted_columns (EURUSD,H1)        12|        410 South Korea    KR   Asia              KRW      
5_select_some_sorted_columns (EURUSD,H1)        13|        484 Mexico         MX   North America     MXN      
5_select_some_sorted_columns (EURUSD,H1)        14|        554 New Zealand    NZ   Australia/Oceania NZD      
5_select_some_sorted_columns (EURUSD,H1)        15|        578 Norway         NO   Europe            NOK      
5_select_some_sorted_columns (EURUSD,H1)        16|        702 Singapore      SG   Asia              SGD      
5_select_some_sorted_columns (EURUSD,H1)        17|        710 South Africa   ZA   Africa            ZAR      
5_select_some_sorted_columns (EURUSD,H1)        18|        724 Spain          ES   Europe            EUR      
5_select_some_sorted_columns (EURUSD,H1)        19|        752 Sweden         SE   Europe            SEK      
5_select_some_sorted_columns (EURUSD,H1)        20|        756 Switzerland    CH   Europe            CHF      
5_select_some_sorted_columns (EURUSD,H1)        21|        826 United Kingdom GB   Europe            GBP      
5_select_some_sorted_columns (EURUSD,H1)        22|        840 United States  US   North America     USD      
5_select_some_sorted_columns (EURUSD,H1)        23|        999 European Union EU   Europe            EUR      

El script ha funcionado correctamente: la columna "COUNTRY_ID" comienza por 0 y termina en 999.


2.6 Seleccionando los resultados agrupados de una columna determinada de la tabla

Ahora, usando el script 6_select_some_grouped_columns.mq5, intentaremos obtener los nombres de los países agrupados por continente. La tarea consiste en obtener, para cada fila de un continente, el número de países incluidos en el mismo. Los países se seleccionan en la columna "NAME". Después de ejecutar el script, aparecerán las siguientes líneas en el diario de registro:

6_select_some_grouped_columns (EURUSD,H1)       #| CONTINENT         COUNT(NAME)
6_select_some_grouped_columns (EURUSD,H1)       -+------------------------------
6_select_some_grouped_columns (EURUSD,H1)       1| Africa                      1 
6_select_some_grouped_columns (EURUSD,H1)       2| Asia                        6 
6_select_some_grouped_columns (EURUSD,H1)       3| Australia/Oceania           2 
6_select_some_grouped_columns (EURUSD,H1)       4| Europe                      9 
6_select_some_grouped_columns (EURUSD,H1)       5| North America               3 
6_select_some_grouped_columns (EURUSD,H1)       6| South America               1 
6_select_some_grouped_columns (EURUSD,H1)       7| World                       1 


El continente "Europe" es el que tiene más países, con 9, mientras que los continentes "Africa" y "South America" solo tienen 1 cada uno. Y también se les une el mundo entero: "World".


2.7 Seleccionando valores únicos para una columna determinada de la tabla

Ahora, usando el script 7_select_distinct_columns.mq5, recopilaremos los valores únicos en la columna "CURRENCY". Hay países en los que se usa la misma moneda. Para evitar repeticiones, ejecutaremos este script, obteniendo en el diario de registro:

7_select_distinct_columns (EURUSD,H1)    1| NZD      
7_select_distinct_columns (EURUSD,H1)    2| EUR      
7_select_distinct_columns (EURUSD,H1)    3| JPY      
7_select_distinct_columns (EURUSD,H1)    4| CAD      
7_select_distinct_columns (EURUSD,H1)    5| AUD      
7_select_distinct_columns (EURUSD,H1)    6| CNY      
7_select_distinct_columns (EURUSD,H1)    7| SGD      
7_select_distinct_columns (EURUSD,H1)    8| BRL      
7_select_distinct_columns (EURUSD,H1)    9| MXN      
7_select_distinct_columns (EURUSD,H1)   10| ZAR      
7_select_distinct_columns (EURUSD,H1)   11| HKD      
7_select_distinct_columns (EURUSD,H1)   12| INR      
7_select_distinct_columns (EURUSD,H1)   13| NOK      
7_select_distinct_columns (EURUSD,H1)   14| USD      
7_select_distinct_columns (EURUSD,H1)   15| GBP      
7_select_distinct_columns (EURUSD,H1)   16| CHF      
7_select_distinct_columns (EURUSD,H1)   17| KRW      
7_select_distinct_columns (EURUSD,H1)   18| SEK      
7_select_distinct_columns (EURUSD,H1)   19| ALL      

Así, el calendario tendrá eventos para un total de 18 monedas y un grupo de eventos que se aplicará a todas ellas.

Podemos ver fácilmente que los métodos de selección de los resultados agrupados y de selección de los valores únicos son similares. Vamos a demostrarlo con un ejemplo.

El script 8_compare_ grouped_and_distinct_columns.mq5 imprime en el diario de registro los siguientes resultados:

8_compare_ grouped_and_distinct_columns (EURUSD,H1)     
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     Method CDatabase::SelectFromGroupBy()
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     #| CONTINENT        
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     -+------------------
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     1| Africa            
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     2| Asia              
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     3| Australia/Oceania 
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     4| Europe            
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     5| North America     
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     6| South America     
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     7| World             
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     Method CDatabase::SelectDistinctFrom()
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     #| CONTINENT        
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     -+------------------
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     1| Australia/Oceania 
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     2| Europe            
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     3| Asia              
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     4| North America     
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     5| South America     
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     6| Africa            
8_compare_ grouped_and_distinct_columns (EURUSD,H1)     7| World             


Los métodos retornarán los mismos resultados porque para el primer método hemos definido la columna "CONTINENT" como columna de agrupación (campo). Curiosamente, el primer método también ha clasificado nuestra muestra.


2.8 Seleccionando los valores únicos clasificados de una columna determinada de la tabla

Los valores de la columna "CURRENCY" han sido asignados por el script 7_select_distinct_columns.mq5 de forma no clasificada. Ahora crearemos una muestra ya con la clasificación (script 9_select_sorted_distinct_columns.mq5). Digamos que la columna "COUNTRY_ID" será el criterio de clasificación. El resultado de la manipulación en el diario de registro será:

9_select_sorted_distinct_columns (EURUSD,H1)     #| CURRENCY
9_select_sorted_distinct_columns (EURUSD,H1)    --+---------
9_select_sorted_distinct_columns (EURUSD,H1)     1| ALL      
9_select_sorted_distinct_columns (EURUSD,H1)     2| AUD      
9_select_sorted_distinct_columns (EURUSD,H1)     3| BRL      
9_select_sorted_distinct_columns (EURUSD,H1)     4| CAD      
9_select_sorted_distinct_columns (EURUSD,H1)     5| CNY      
9_select_sorted_distinct_columns (EURUSD,H1)     6| EUR      
9_select_sorted_distinct_columns (EURUSD,H1)     7| HKD      
9_select_sorted_distinct_columns (EURUSD,H1)     8| INR      
9_select_sorted_distinct_columns (EURUSD,H1)     9| JPY      
9_select_sorted_distinct_columns (EURUSD,H1)    10| KRW      
9_select_sorted_distinct_columns (EURUSD,H1)    11| MXN      
9_select_sorted_distinct_columns (EURUSD,H1)    12| NZD      
9_select_sorted_distinct_columns (EURUSD,H1)    13| NOK      
9_select_sorted_distinct_columns (EURUSD,H1)    14| SGD      
9_select_sorted_distinct_columns (EURUSD,H1)    15| ZAR      
9_select_sorted_distinct_columns (EURUSD,H1)    16| SEK      
9_select_sorted_distinct_columns (EURUSD,H1)    17| CHF      
9_select_sorted_distinct_columns (EURUSD,H1)    18| GBP      
9_select_sorted_distinct_columns (EURUSD,H1)    19| USD      


Ahora todas las monedas están clasificadas. El orden de clasificación por defecto será ascendente.


2.9 Seleccionando algunas columnas de una tabla según una condición

Antes hemos creado una consulta SQL para obtener las columnas de una tabla. Ahora vamos a hacer que resulte posible obtener las columnas si se cumple alguna condición. Supongamos que queremos seleccionar países cuyo ID sea igual o superior a 392, e igual o inferior a 840. Esta tarea se resolverá con el script 10_select_some_columns_where.mq5.

Después de ejecutar el script, veremos lo siguiente en el diario de registro:

10_select_some_columns_where (EURUSD,H1)         #| COUNTRY_ID NAME           CODE CONTINENT         CURRENCY
10_select_some_columns_where (EURUSD,H1)        --+----------------------------------------------------------
10_select_some_columns_where (EURUSD,H1)         1|        392 Japan          JP   Asia              JPY      
10_select_some_columns_where (EURUSD,H1)         2|        410 South Korea    KR   Asia              KRW      
10_select_some_columns_where (EURUSD,H1)         3|        484 Mexico         MX   North America     MXN      
10_select_some_columns_where (EURUSD,H1)         4|        554 New Zealand    NZ   Australia/Oceania NZD      
10_select_some_columns_where (EURUSD,H1)         5|        578 Norway         NO   Europe            NOK      
10_select_some_columns_where (EURUSD,H1)         6|        702 Singapore      SG   Asia              SGD      
10_select_some_columns_where (EURUSD,H1)         7|        710 South Africa   ZA   Africa            ZAR      
10_select_some_columns_where (EURUSD,H1)         8|        724 Spain          ES   Europe            EUR      
10_select_some_columns_where (EURUSD,H1)         9|        752 Sweden         SE   Europe            SEK      
10_select_some_columns_where (EURUSD,H1)        10|        756 Switzerland    CH   Europe            CHF      
10_select_some_columns_where (EURUSD,H1)        11|        826 United Kingdom GB   Europe            GBP      
10_select_some_columns_where (EURUSD,H1)        12|        840 United States  US   North America     USD      


Es decir, la muestra comienza con el código de país, que es 392, y termina con el código 840. 


2.10 Seleccionando algunas columnas clasificadas en una tabla según una condición

Vamos a complicar la tarea anterior. Para ello, añadiremos un criterio de clasificación a la muestra, a saber, si un país pertenece o no a un continente. El problema actual se resolverá en el script 11_select_some_sorted_columns_where.mq5. Después de ejecutarlo, veremos varias líneas como estas en el diario de registro:

11_select_some_sorted_columns_where (EURUSD,H1)  #| COUNTRY_ID NAME           CODE CONTINENT         CURRENCY
11_select_some_sorted_columns_where (EURUSD,H1) --+----------------------------------------------------------
11_select_some_sorted_columns_where (EURUSD,H1)  1|        710 South Africa   ZA   Africa            ZAR      
11_select_some_sorted_columns_where (EURUSD,H1)  2|        392 Japan          JP   Asia              JPY      
11_select_some_sorted_columns_where (EURUSD,H1)  3|        410 South Korea    KR   Asia              KRW      
11_select_some_sorted_columns_where (EURUSD,H1)  4|        702 Singapore      SG   Asia              SGD      
11_select_some_sorted_columns_where (EURUSD,H1)  5|        554 New Zealand    NZ   Australia/Oceania NZD      
11_select_some_sorted_columns_where (EURUSD,H1)  6|        578 Norway         NO   Europe            NOK      
11_select_some_sorted_columns_where (EURUSD,H1)  7|        724 Spain          ES   Europe            EUR      
11_select_some_sorted_columns_where (EURUSD,H1)  8|        752 Sweden         SE   Europe            SEK      
11_select_some_sorted_columns_where (EURUSD,H1)  9|        756 Switzerland    CH   Europe            CHF      
11_select_some_sorted_columns_where (EURUSD,H1) 10|        826 United Kingdom GB   Europe            GBP      
11_select_some_sorted_columns_where (EURUSD,H1) 11|        484 Mexico         MX   North America     MXN      
11_select_some_sorted_columns_where (EURUSD,H1) 12|        840 United States  US   North America     USD      


 Como resultado, "South Africa" aparecerá en primer lugar en la muestra, ya que el continente "Africa" aparece en primer lugar en la lista de continentes.


2.11 Actualizando algunas columnas de una tabla según una condición

Supongamos que tenemos la tarea de actualizar las filas de las columnas seleccionadas, y que debemos hacerlo cumpliendo previamente algún tipo de condición.

Vamos a tomar los países asiáticos y a poner a cero para ellos los valores de las columnas "CURRENCY", "CURRENCY_SYMBOL". Esta tarea la realizará el script 12_update_some_columns.mq5.

Los resultados se resumirán en la tabla siguiente:

12_update_some_columns (EURUSD,H1)       #| COUNTRY_ID NAME           CODE CONTINENT         CURRENCY CURRENCY_SYMBOL URL_NAME      
12_update_some_columns (EURUSD,H1)      --+-----------------------------------------------------------------------------------------
12_update_some_columns (EURUSD,H1)       1|        554 New Zealand    NZ   Australia/Oceania NZD      $               new-zealand    
12_update_some_columns (EURUSD,H1)       2|        999 European Union EU   Europe            EUR      €               european-union 
12_update_some_columns (EURUSD,H1)       3|        392 Japan          JP   Asia              None     None            japan          
12_update_some_columns (EURUSD,H1)       4|        124 Canada         CA   North America     CAD      $               canada         
12_update_some_columns (EURUSD,H1)       5|         36 Australia      AU   Australia/Oceania AUD      $               australia      
12_update_some_columns (EURUSD,H1)       6|        156 China          CN   Asia              None     None            china          
12_update_some_columns (EURUSD,H1)       7|        380 Italy          IT   Europe            EUR      €               italy          
12_update_some_columns (EURUSD,H1)       8|        702 Singapore      SG   Asia              None     None            singapore      
12_update_some_columns (EURUSD,H1)       9|        276 Germany        DE   Europe            EUR      €               germany        
12_update_some_columns (EURUSD,H1)      10|        250 France         FR   Europe            EUR      €               france         
12_update_some_columns (EURUSD,H1)      11|         76 Brazil         BR   South America     BRL      R$              brazil         
12_update_some_columns (EURUSD,H1)      12|        484 Mexico         MX   North America     MXN      Mex$            mexico         
12_update_some_columns (EURUSD,H1)      13|        710 South Africa   ZA   Africa            ZAR      R               south-africa   
12_update_some_columns (EURUSD,H1)      14|        344 Hong Kong      HK   Asia              None     None            hong-kong      
12_update_some_columns (EURUSD,H1)      15|        356 India          IN   Asia              None     None            india          
12_update_some_columns (EURUSD,H1)      16|        578 Norway         NO   Europe            NOK      Kr              norway         
12_update_some_columns (EURUSD,H1)      17|        840 United States  US   North America     USD      $               united-states  
12_update_some_columns (EURUSD,H1)      18|        826 United Kingdom GB   Europe            GBP      £               united-kingdom 
12_update_some_columns (EURUSD,H1)      19|        756 Switzerland    CH   Europe            CHF      ₣               switzerland    
12_update_some_columns (EURUSD,H1)      20|        410 South Korea    KR   Asia              None     None            south-korea    
12_update_some_columns (EURUSD,H1)      21|        724 Spain          ES   Europe            EUR      €               spain          
12_update_some_columns (EURUSD,H1)      22|        752 Sweden         SE   Europe            SEK      Kr              sweden         
12_update_some_columns (EURUSD,H1)      23|          0 Worldwide      WW   World             ALL                      worldwide      


2.12 Sustituyendo y añadiendo algunas filas de la tabla

Sigamos con las tablas. Ahora intentaremos reemplazar algunas de las filas de la tabla seleccionada.

Para el país "Mexico" en la columna "CURRENCY_SYMBOL", sustituiremos el símbolo actual "Mex$" por "Peso mexicano". Luego asignaremos esta tarea al script 13_replace_some_rows.mq5.

En la versión actual de la tabla COUNTRIES, México se corresponde con esta entrada:

COUNTRY_ID
NAME
CODE
CONTINENT
CURRENCY
CURRENCY_SYMBOL
URL_NAME
484 Mexico
MX
North America
MXN
Mex$


mexico


Para sustituir esta fila en la tabla, deberemos especificar algún valor único para la fila seleccionada. De lo contrario, SQLite no entenderá lo que queremos sustituir.

Supongamos que este valor es el nombre del país (columna NAME). La función de sustitución se representará entonces en el código de la forma siguiente:

//--- the replaced row for "COUNTRY_NAME=Mexico"
string col_names[]=
  {
   "NAME", "CURRENCY_SYMBOL"
  };
string col_vals[2];
col_vals[0]=::StringFormat("'%s'", "Mexico");
col_vals[1]=::StringFormat("'%s'", "Peso mexicano");
if(!db_obj.Replace(col_names, col_vals))
  {
   db_obj.Close();
   return;
  }


Al ejecutar el script, aparecerá este error:

11_replace_some_rows (EURUSD,H1)        database error, NOT NULL constraint failed: COUNTRIES.COUNTRY_ID
11_replace_some_rows (EURUSD,H1)        CDatabase::Replace: failed with code 5619


Claramente se ha infringido la restricción NOT NULL. La cuestión es que originalmente, al crearse la tabla, especificamos que la columna COUNTRY_ID no podía contener un valor nulo. Por lo tanto, deberemos añadir un valor para esta columna. Y para evitar obtener una fila medio vacía, añadiremos valores para todas las columnas.

//--- the replaced row for "COUNTRY_NAME=Mexico"
string col_names[]=
  {
   "COUNTRY_ID", "NAME", "CODE",
   "CONTINENT", "CURRENCY", "CURRENCY_SYMBOL",
   "URL_NAME"
  };
string col_vals[7];
col_vals[0]=::StringFormat("%I64u", 484);
col_vals[1]=::StringFormat("'%s'", "Mexico");
col_vals[2]=::StringFormat("'%s'", "MX");
col_vals[3]=::StringFormat("'%s'", "North America");
col_vals[4]=::StringFormat("'%s'", "MXN");
col_vals[5]=::StringFormat("'%s'", "Peso mexicano");
col_vals[6]=::StringFormat("'%s'", "mexico");
if(!db_obj.Replace(col_names, col_vals))
  {
   db_obj.Close();
   return;
  }

El script funcionará ahora con total normalidad. En el diario de registro tendremos ahora entradas como esta:

13_replace_some_rows (EURUSD,H1)         'Mexico' row before replacement
13_replace_some_rows (EURUSD,H1)        #| COUNTRY_ID NAME   CODE CONTINENT     CURRENCY CURRENCY_SYMBOL URL_NAME
13_replace_some_rows (EURUSD,H1)        -+-----------------------------------------------------------------------
13_replace_some_rows (EURUSD,H1)        1|        484 Mexico MX   North America MXN      Mex$            mexico   
13_replace_some_rows (EURUSD,H1)        
13_replace_some_rows (EURUSD,H1)         'Mexico' row after replacement
13_replace_some_rows (EURUSD,H1)        #| COUNTRY_ID NAME   CODE CONTINENT     CURRENCY CURRENCY_SYMBOL URL_NAME
13_replace_some_rows (EURUSD,H1)        -+-----------------------------------------------------------------------
13_replace_some_rows (EURUSD,H1)        1|        484 Mexico MX   North America MXN      Peso mexicano   mexico   


Cabe señalar que si no hubiera ninguna línea con datos sobre México, simplemente se añadiría esta línea. Es decir, la operación de sustitución es también una operación de adición de filas de la tabla.


2.13 Eliminando algunas filas de la tabla

Veamos ahora cómo podemos acortar las filas de la tabla en lugar de expandirlas. Para ello, crearemos el script 14_delete_some_rows.mq5, que borrará según la consulta las filas de la tabla seleccionada relacionadas con Asia.

Después de ejecutar el script, imprimiremos una tabla resumen:

14_delete_some_rows (EURUSD,H1)  #| COUNTRY_ID NAME           CODE CONTINENT         CURRENCY CURRENCY_SYMBOL URL_NAME      
14_delete_some_rows (EURUSD,H1) --+-----------------------------------------------------------------------------------------
14_delete_some_rows (EURUSD,H1)  1|        554 New Zealand    NZ   Australia/Oceania NZD      $               new-zealand    
14_delete_some_rows (EURUSD,H1)  2|        999 European Union EU   Europe            EUR      €               european-union 
14_delete_some_rows (EURUSD,H1)  3|        124 Canada         CA   North America     CAD      $               canada         
14_delete_some_rows (EURUSD,H1)  4|         36 Australia      AU   Australia/Oceania AUD      $               australia      
14_delete_some_rows (EURUSD,H1)  5|        380 Italy          IT   Europe            EUR      €               italy          
14_delete_some_rows (EURUSD,H1)  6|        276 Germany        DE   Europe            EUR      €               germany        
14_delete_some_rows (EURUSD,H1)  7|        250 France         FR   Europe            EUR      €               france         
14_delete_some_rows (EURUSD,H1)  8|         76 Brazil         BR   South America     BRL      R$              brazil         
14_delete_some_rows (EURUSD,H1)  9|        710 South Africa   ZA   Africa            ZAR      R               south-africa   
14_delete_some_rows (EURUSD,H1) 10|        578 Norway         NO   Europe            NOK      Kr              norway         
14_delete_some_rows (EURUSD,H1) 11|        840 United States  US   North America     USD      $               united-states  
14_delete_some_rows (EURUSD,H1) 12|        826 United Kingdom GB   Europe            GBP      £               united-kingdom 
14_delete_some_rows (EURUSD,H1) 13|        756 Switzerland    CH   Europe            CHF      ₣               switzerland    
14_delete_some_rows (EURUSD,H1) 14|        724 Spain          ES   Europe            EUR      €               spain          
14_delete_some_rows (EURUSD,H1) 15|        752 Sweden         SE   Europe            SEK      Kr              sweden         
14_delete_some_rows (EURUSD,H1) 16|          0 Worldwide      WW   World             ALL                      worldwide      
14_delete_some_rows (EURUSD,H1) 17|        484 Mexico         MX   North America     MXN      Peso mexicano   mexico         


No hemos encontrado filas relacionadas con el continente asiático.


2.14 Añadiendo columnas a una tabla

Las operaciones de tabla incluyen la tarea bastante común de añadir nuevas columnas.

Supongamos que necesitamos ampliar nuestra tabla "COUNTRIES" y añadir una columna que contenga el número de eventos macroeconómicos que entran en el calendario.

La tarea será realizada por el script 15_add_new_column.mq5.

Después de ejecutar el script, comprobaremos la tabla (fig. 5). Tiene la nueva columna "EVENTS_NUM".


Nueva columna "EVENTS_NUM" en la tabla COUNTRIES

Fig.5 Nueva columna "EVENTS_NUM" en la tabla COUNTRIES


2.15 Renombrando las columnas de una tabla

Si necesitamos renombrar una columna de la tabla, usaremos el método CDatabase::RenameColumn(const string _curr_name, const string _new_name). Los parámetros son el nombre de la columna actual y el nombre de la nueva columna. El script 16_rename_column.mq5 cambia el nombre de la columna "EVENTS_NUM" a "EVENTS_NUMBER".


Columna “EVENTS_NUMBER” renombrada en la tabla COUNTRIES

Fig.6 Columna “EVENTS_NUMBER” renombrada en la tabla COUNTRIES


La tabla tendrá ahora el aspecto siguiente (Fig. 6).


2.16 Combinando las filas de algunas columnas

Supongamos que queremos combinar los resultados de las muestras en una tabla. El método CDatabase::Union() será el adecuado para este propósito. La tarea será realizada por el script 17_union_some_columns.mq5.

Supongamos que tenemos 2 tablas “EUROPEAN_COUNTRIES” y “NORTH_AMERICAN_COUNTRIES”. La primera incluirá a los países europeos, mientras que la segunda incluirá a los norteamericanos. Crearemos previamente las tablas para combinar sus filas. Cada una de las tablas será una muestra resultante de la primera tabla "COUNTRIES". En el código, tendrá el aspecto que sigue:

//--- create 2 tables
   string table1_name, table2_name, sql_request;
   table1_name="EUROPEAN_COUNTRIES";
   table2_name="NORTH_AMERICAN_COUNTRIES";
   sql_request="SELECT COUNTRY_ID AS id, NAME AS name, CURRENCY "
               "as currency FROM COUNTRIES "
               "WHERE CONTINENT='North America'";
   if(!db_obj.CreateTableAs(table2_name, sql_request, true))
      {
      db_obj.Close();
      return;
      }
   db_obj.FinalizeSqlRequest();
   sql_request="SELECT COUNTRY_ID AS id, NAME AS name, CURRENCY "
               "as currency FROM COUNTRIES "
               "WHERE CONTINENT='Europe'";
   if(!db_obj.CreateTableAs(table1_name, sql_request, true))
      {
      db_obj.Close();
      return;
      }
   db_obj.FinalizeSqlRequest();


A medida que se ejecute el script, obtendremos estas entradas en el diario de registro:

16_union_some_columns (EURUSD,H1)        #|  id name           currency
16_union_some_columns (EURUSD,H1)       --+----------------------------
16_union_some_columns (EURUSD,H1)        1| 124 Canada         CAD      
16_union_some_columns (EURUSD,H1)        2| 250 France         EUR      
16_union_some_columns (EURUSD,H1)        3| 276 Germany        EUR      
16_union_some_columns (EURUSD,H1)        4| 380 Italy          EUR      
16_union_some_columns (EURUSD,H1)        5| 484 Mexico         MXN      
16_union_some_columns (EURUSD,H1)        6| 578 Norway         NOK      
16_union_some_columns (EURUSD,H1)        7| 724 Spain          EUR      
16_union_some_columns (EURUSD,H1)        8| 752 Sweden         SEK      
16_union_some_columns (EURUSD,H1)        9| 756 Switzerland    CHF      
16_union_some_columns (EURUSD,H1)       10| 826 United Kingdom GBP      
16_union_some_columns (EURUSD,H1)       11| 840 United States  USD      
16_union_some_columns (EURUSD,H1)       12| 999 European Union EUR      


La muestra resultante incluirá a países de Europa y Norteamérica.


2.17 Diferencias en el muestreo

Supongamos que tenemos dos muestras, y que debemos encontrar registros en la primera muestra que no se encuentren en la segunda. Aquí es donde entrará en juego el método CDatabase::Except().

Por ejemplo, “COUNTRIES” y “EUROPEAN_COUNTRIES”. Y veremos qué países quedarán si aplicamos el operador EXCEPT a la primera tabla.

La solución está codificada en el script 18_except_some_columns.mq5.

Como resultado de la ejecución del programa se mostrarán las siguientes líneas:

18_except_some_columns (EURUSD,H1)      #| COUNTRY_ID NAME          CURRENCY
18_except_some_columns (EURUSD,H1)      -+----------------------------------
18_except_some_columns (EURUSD,H1)      1|          0 Worldwide     ALL      
18_except_some_columns (EURUSD,H1)      2|         36 Australia     AUD      
18_except_some_columns (EURUSD,H1)      3|         76 Brazil        BRL      
18_except_some_columns (EURUSD,H1)      4|        124 Canada        CAD      
18_except_some_columns (EURUSD,H1)      5|        484 Mexico        MXN      
18_except_some_columns (EURUSD,H1)      6|        554 New Zealand   NZD      
18_except_some_columns (EURUSD,H1)      7|        710 South Africa  ZAR      
18_except_some_columns (EURUSD,H1)      8|        840 United States USD      


Resulta sencillo ver que esto ha dado como resultado una muestra de países que no incluye a los países europeos. Tampoco hay asiáticos. Estos se han eliminado antes.


2,18 Cruce de muestras

Ahora vamos a intentar averiguar no en qué se diferencian las muestras, sino qué tienen en común. Es decir, la tarea consistirá en encontrar filas comunes de muestras.

En primer lugar, actualizaremos la tabla "COUNTRIES" y la devolveremos a su forma original, que incluía los países asiáticos.

Luego crearemos dos tablas temporales con las columnas "id", "name" y "currency". La primera incluiría los países con un valor en la columna COUNTRY_ID igual o inferior a 578, mientras que la segunda incluirá los países con un valor en la misma columna igual o superior a 392.

//--- create temporary tables
string table1_name, table2_name, sql_request;
table1_name="Table1";
table2_name="Table2";
sql_request="SELECT COUNTRY_ID AS id, NAME AS name, CURRENCY "
            "as currency FROM COUNTRIES "
            "WHERE COUNTRY_ID<=578";
if(!db_obj.CreateTableAs(table1_name, sql_request, true, true))
  {
   db_obj.Close();
   return;
  }
db_obj.FinalizeSqlRequest();
//--- print the temporary table
string temp_col_names[]= {"*"};
if(db_obj.SelectTable(table1_name, true))
   if(db_obj.SelectFrom(temp_col_names))
     {
      ::Print("   \nTable #1: ");
      db_obj.PrintSqlRequest();
      db_obj.FinalizeSqlRequest();
     }
sql_request="SELECT COUNTRY_ID AS id, NAME AS name, CURRENCY "
            "as currency FROM COUNTRIES "
            "WHERE COUNTRY_ID>=392";
if(!db_obj.CreateTableAs(table2_name, sql_request, true, true))
  {
   db_obj.Close();
   return;
  }
db_obj.FinalizeSqlRequest();
//--- print the temporary table
if(db_obj.SelectTable(table2_name, true))
   if(db_obj.SelectFrom(temp_col_names))
     {
      ::Print("   \nTable #2: ");
      db_obj.PrintSqlRequest();
      db_obj.FinalizeSqlRequest();
     }

Aprovecharemos el método CDatabase::Intersect() en el script 19_intersect_some_columns.mq5. El resultado serán líneas como ésta en el diario de registro:

19_intersect_some_columns (EURUSD,H1)   #|  id name        currency
19_intersect_some_columns (EURUSD,H1)   -+-------------------------
19_intersect_some_columns (EURUSD,H1)   1| 392 Japan       JPY      
19_intersect_some_columns (EURUSD,H1)   2| 410 South Korea KRW      
19_intersect_some_columns (EURUSD,H1)   3| 484 Mexico      MXN      
19_intersect_some_columns (EURUSD,H1)   4| 554 New Zealand NZD      
19_intersect_some_columns (EURUSD,H1)   5| 578 Norway      NOK      


El script ha funcionado correctamente: hemos obtenido una lista de países con un valor de ID mínimo de 392 y un valor de ID máximo de 578.


2.19 Creando vistas

Una vista (view) es una especie de tabla virtual. La ventaja es que puede mostrar los datos seleccionados de cualquier otra tabla.

Crearemos las vistas usando los métodos bool CDatabase::CreateView() y bool CDatabase::CreateViewWhere(). El primero crea algún tipo de vista incondicional, mientras que el segundo la crea según una condición especificada.

Vamos a analizar este ejemplo. Tenemos una tabla llamada COUNTRIES. Supongamos que todos los países de las columnas “NAME”, “CONTINENT”, “CURRENCY” deben seleccionarse en una nueva tabla virtual.

Resolveremos esta tarea utilizando el script 20_create_view.mq5. En la salida obtendremos el resultado: "All_countries" (fig. 7).


Vista “All_countries”

Figura 7 Vista “All_countries” 


Ahora complicaremos el ejemplo y seleccionaremos solo países europeos. De esto se encargará el script 21_create_view_where.mq5. Finalmente, terminaremos con una tabla virtual que solo contiene países europeos (Fig.8).


Vista “European”

Fig.8 Vista “European”


Por un lado, las vistas no son tablas completas: no se pueden añadir, eliminar o actualizar filas en ellas; por otro, se pueden utilizar para añadir cómodamente los resultados de consultas complejas, y también para seleccionar columnas individuales cambiando sus nombres, sin afectar a las relaciones entre las propias tablas.


2.20 Eliminando vistas

Podemos eliminar una vista previamente creada utilizando el método CDatabase::DropView().

El método es similar a su homólogo, que elimina las tablas DropTable(). En los ejemplos anteriores, era el método de eliminación de la vista el que se llamaba antes de crear la misma.

Vamos a decir algunas palabras sobre la construcción IF EXISTS. Si intentamos eliminar una vista inexistente con esta construcción, el método retornará true, en caso contrario, devolverá false.

Veamos cómo funciona el script 22_drop_view.mq5.

//--- drop a view
string table_name="COUNTRIES";
if(db_obj.SelectTable(table_name))
   for(int idx=0; idx<2; idx++)
     {
      string view_name=::StringFormat("European%d", idx+1);
      bool if_exists=idx;
      if(db_obj.DropView(view_name, if_exists))
         ::PrintFormat("A view \"%s\" has been successfully dropped!", view_name);
      db_obj.FinalizeSqlRequest();
     }

En primer lugar, intentaremos eliminar la vista inexistente "European_countries1" sin invocar "IF EXISTS". Como resultado, obtendremos el error 5601:

22_drop_view (EURUSD,H1)        database error, no such view: European1
22_drop_view (EURUSD,H1)        CDatabase::Select: failed with code 5601
22_drop_view (EURUSD,H1)        A view "European2" has been successfully dropped!


A continuación, el script intentará eliminar la vista "European_countries2", que tampoco existe, pero usando ya "IF EXISTS". La eliminación de la segunda vista se realizará correctamente, aunque en realidad no se haya producido ninguna eliminación.


2.21 Cambiando el nombre de la tabla

Supongamos que tenemos la tarea de renombrar la propia tabla. Para ello, usaremos el método CDatabase::RenameTable(). El script 23_rename_table.mq5 ejecutará el comando de cambio de nombre.


Renombrando la tabla COUNTRIES1

Fig.9 Renombrando la tabla COUNTRIES1


De este modo, la tabla actual se llamará "COUNTRIES1" (Fig.9).


3. Base de datos de eventos macroeconómicos

En este apartado, abordaremos la creación de una base de datos relacional con los eventos macroeconómicos recogidos en el Calendario.

Así que, en primer lugar, crearemos un esquema con las tablas que compondrán la futura base de datos. Debo señalar que en el artículo "Recetas MQL5 - Calendario Económico" ya hemos presentado la relación entre las estructuras de calendario. Por lo tanto, en nuestro caso, resultará bastante sencillo crear tablas y construir relaciones para la base de datos.


3.1 Tablas y conexiones relacionales

Tendremos un total de 3 tablas de origen en la base de datos:

  1. COUNTRIES;
  2. EVENTS;
  3. EVENT_VALUES.

Las conexiones relacionales entre las tablas se muestran en la Fig.10.


Esquema de conexiones entre tablas en la base de datos Calendar_DB

Fig.10 Esquema de conexiones entre tablas en la base de datos Calendar_DB


La tabla COUNTRIES se convertirá en la tabla madre de la tabla EVENTS. Esta última, a su vez, se convertirá en la tabla hija de la primera.

La clave primaria de la tabla COUNTRIES es la columna (campo) "COUNTRY_ID". En el esquema va precedida del signo "+". Para la tabla EVENTS, esta clave será la columna "EVENT_ID", mientras que la columna "COUNTRY_ID" será una clave externa. En el esquema va precedida del símbolo "#".

La tabla EVENTS se convertirá en la tabla madre de la tabla EVENT_VALUES, mientras que la segunda se convertirá en la tabla hija de la primera.

En la tabla EVENT_VALUES, la clave principal será la columna (campo) "VALUE_ID", mientras que la clave externa será "EVENT_ID".

Las claves son necesarias precisamente para implementar las conexiones entre las tablas anteriormente descritas. Los enlaces, a su vez, contribuyen a la integridad de los datos de la base.

Las conexiones entre las tres tablas van de una a muchas (1...*). Probablemente, no debería ser demasiado difícil descifrarlas. La primera conexión entre países y acontecimientos puede imaginarse del siguiente modo: un país tiene muchos eventos macroeconómicos, mientras que un evento solo tiene un país. La segunda relación entre los eventos y los valores de los mismos puede ilustrarse del siguiente modo: un evento tiene muchos valores y cualquier valor solo tiene un evento.

Vamos a pasar al código. En el script sCreateAndFillCalendarDB.mq5 implementaremos los siguientes pasos:

  1. la creación de una base de datos de calendarios;
  2. la creación de tablas de bases de datos;
  3. el rellenando las tablas.

Veamos, por ejemplo, cómo se crea la tabla EVENTS. La consulta final para crear esta tabla tendrá el aspecto siguiente:

CREATE TABLE IF NOT EXISTS EVENTS (
    EVENT_ID   [UNSIGNED BIG INT] PRIMARY KEY
                                  NOT NULL,
    TYPE       TEXT,
    SECTOR     TEXT,
    FREQUENCY  TEXT,
    TIME_MODE  TEXT,
    COUNTRY_ID [UNSIGNED BIG INT] NOT NULL,
    UNIT       TEXT,
    IMPORTANCE TEXT,
    MULTIPLIER TEXT,
    DIGITS     [UNSIGNED INT],
    SOURCE     TEXT,
    CODE       TEXT,
    NAME       TEXT,
    FOREIGN KEY (
        COUNTRY_ID
    )
    REFERENCES COUNTRIES (COUNTRY_ID) ON UPDATE CASCADE
                                      ON DELETE CASCADE
)


Resultan especialmente interesantes las líneas en las que se crea la clave externa. La línea FOREIGN KEY (COUNTRY_ID) indica que la tabla tiene una clave externa para el campo COUNTRY_ID. La construcción REFERENCES COUNTRIES(COUNTRY_ID) se usa para hacer referencia a la tabla madre COUNTRIES.

Las expresiones ON UPDATE CASCADE y ON DELETE CASCADE significan que si la fila asociada de la tabla madre se elimina o modifica en la tabla hija, las filas también se eliminarán o modificarán.

En cuanto al rellenado de las tablas, a continuación mostramos un bloque de código en el que se cumplimenta la tabla "COUNTRIES".

//--- Table 1
MqlCalendarCountry calendar_countries[];
table_name="COUNTRIES";
if(db_obj.SelectTable(table_name))
   if(db_obj.EmptyTable())
     {
      db_obj.FinalizeSqlRequest();
      string col_names[]=
        {
         "COUNTRY_ID",     // 1
         "NAME",           // 2
         "CODE",           // 3
         "CONTINENT",      // 4
         "CURRENCY",       // 5
         "CURRENCY_SYMBOL",// 6
         "URL_NAME"        // 7
        };
      CiCalendarInfo calendar_info;
      if(calendar_info.Init())
        {
         if(calendar_info.GetCountries(calendar_countries))
           {
            if(db_obj.TransactionBegin())
               for(int c_idx=0; c_idx<::ArraySize(calendar_countries); c_idx++)
                 {
                  MqlCalendarCountry curr_country=calendar_countries[c_idx];
                  string col_vals[];
                  ::ArrayResize(col_vals, 7);
                  col_vals[0]=::StringFormat("%I64u", curr_country.id);
                  col_vals[1]=::StringFormat("'%s'", curr_country.name);
                  col_vals[2]=::StringFormat("'%s'", curr_country.code);
                  col_vals[3]="NULL";
                  SCountryByContinent curr_country_continent_data;
                  if(curr_country_continent_data.Init(curr_country.code))
                     col_vals[3]=::StringFormat("'%s'",
                                                curr_country_continent_data.ContinentDescription());
                  col_vals[4]=::StringFormat("'%s'", curr_country.currency);
                  col_vals[5]=::StringFormat("'%s'", curr_country.currency_symbol);
                  col_vals[6]=::StringFormat("'%s'", curr_country.url_name);
                  if(!db_obj.InsertSingleRow(col_names, col_vals))
                    {
                     db_obj.TransactionRollback();
                     db_obj.Close();
                     return;
                    }
                  db_obj.FinalizeSqlRequest();
                 }
            if(!db_obj.TransactionCommit())
               ::PrintFormat("Failed to complete transaction execution, error %d", ::GetLastError());
           }
         //--- print
         if(db_obj.PrintTable()<0)
            ::PrintFormat("Failed to print the table \"%s\", error %d", table_name, ::GetLastError());
        }
     }


Primero deberemos seleccionar la tabla utilizando el método CDatabase::SelectTable(). Aquí podemos hacer una analogía con la forma en que se selecciona una posición comercial utilizando la función nativa ::PositionSelect() para su posterior procesamiento.

A continuación, el método CDatabase::EmptyTable() despeja preliminarmente la tabla.

Luego recorre los países y rellena la tabla columna por columna

  • "COUNTRY_ID",
  • "COUNTRY_NAME",
  • "COUNTRY_CODE",
  • "CONTINENT",
  • "CURRENCY",
  • "CURRENCY_SYMBOL",
  • "URL_NAME".

La inserción de la fila resumen en la tabla se realiza con el método CDatabase::InsertSingleRow(). Tenga en cuenta que, a la hora de rellenar la tabla, existe un mecanismo transaccional. Para obtener más información sobre ello, le recomendamos leer "Acelerando las transacciones con el envoltorio en DatabaseTransactionBegin()/DatabaseTransactionCommit()".

Los resultados de las tres tablas son los siguientes: la tabla COUNTRIES contiene 23 entradas, la tabla EVENTS contiene 1500 entradas y la tabla EVENT_VALUES contiene 158.696 entradas (Fig.11).


Tabla EVENT_VALUES rellenada

Fig.11 Tabla rellenada EVENT_VALUES


Ahora que tenemos los datos, podemos comenzar a obtener la información: vamos a generar las consultas.


3.2 Consultas a la base de datos

En general, todas las consultas a bases de datos pueden dividirse en dos grupos:

1) consultas que recuperan información de la base de datos;

2) consultas que modifican los datos de la base de datos.

Primero vamos a trabajar con ejemplos de cómo recuperar información de la base de datos de calendarios.


3.2.1 Muestra del número de eventos por país

Empezaremos preguntando a la base de datos cuántos eventos macroeconómicos hay por país. Crearemos la siguiente consulta accediendo a la tabla "EVENTS":

SELECT COUNTRY_ID AS id,
       COUNT(EVENT_ID) AS events_num
  FROM EVENTS
 GROUP BY COUNTRY_ID


En el código MQL5, dicha consulta se implementa de la siguiente manera:

//--- 1) group events number by country id
string table_name="EVENTS";
if(db_obj.SelectTable(table_name))
  {
   string col_names_to_select[]=
     {
      "COUNTRY_ID AS id", "COUNT(EVENT_ID) AS events_num"
     };
   string gr_names[]=
     {
      "COUNTRY_ID"
     };
   if(!db_obj.SelectFromGroupBy(col_names_to_select, gr_names))
     {
      db_obj.Close();
      return;
     }
//--- print the SQL request
   if(db_obj.PrintSqlRequest()<0)
      ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError());
   db_obj.FinalizeSqlRequest();


Y en el registro del terminal, en la salida obtendremos la muestra de las columnas originales "COUNTRY_ID" y "COUNT(EVENT_ID)":

sRequest1 (EURUSD,H1)    #|  id events_num
sRequest1 (EURUSD,H1)   --+---------------
sRequest1 (EURUSD,H1)    1|   0          7 
sRequest1 (EURUSD,H1)    2|  36         85 
sRequest1 (EURUSD,H1)    3|  76         55 
sRequest1 (EURUSD,H1)    4| 124         74 
sRequest1 (EURUSD,H1)    5| 156         40 
sRequest1 (EURUSD,H1)    6| 250         43 
sRequest1 (EURUSD,H1)    7| 276         62 
sRequest1 (EURUSD,H1)    8| 344         26 
sRequest1 (EURUSD,H1)    9| 356         57 
sRequest1 (EURUSD,H1)   10| 380         52 
sRequest1 (EURUSD,H1)   11| 392        124 
sRequest1 (EURUSD,H1)   12| 410         36 
sRequest1 (EURUSD,H1)   13| 484         47 
sRequest1 (EURUSD,H1)   14| 554         82 
sRequest1 (EURUSD,H1)   15| 578         47 
sRequest1 (EURUSD,H1)   16| 702         27 
sRequest1 (EURUSD,H1)   17| 710         54 
sRequest1 (EURUSD,H1)   18| 724         39 
sRequest1 (EURUSD,H1)   19| 752         59 
sRequest1 (EURUSD,H1)   20| 756         40 
sRequest1 (EURUSD,H1)   21| 826        115 
sRequest1 (EURUSD,H1)   22| 840        247 
sRequest1 (EURUSD,H1)   23| 999         82 


Estoy de acuerdo con que la muestra no parece muy legible, ya que la columna "id" es el identificador del país, y no el nombre del mismo, pero los nombres de los países están en otra tabla: "COUNTRIES".

Para obtener el nombre de un país y el número de eventos del mismo, deberemos crear una consulta compuesta (una consulta dentro de otra).

La primera versión de esta tendrá el aspecto siguiente:

SELECT c.NAME AS country,
       ev.events_num AS events_number
  FROM COUNTRIES c
       JOIN
       (
           SELECT COUNTRY_ID AS id,
                  COUNT(EVENT_ID) AS events_num
             FROM EVENTS
            GROUP BY COUNTRY_ID
       )
       AS ev ON c.COUNTRY_ID = ev.id


Esta variante usa la consulta que creamos al principio, pero ahora ha pasado a formar parte de otra consulta, cambiando así su forma a la de una subconsulta. 

Y la segunda variante de la consulta puede implementarse en forma de СТЕ

WITH ev_cnt AS (
    SELECT COUNTRY_ID AS id,
           COUNT(EVENT_ID) AS events_num
      FROM EVENTS
     GROUP BY COUNTRY_ID
)
SELECT c.NAME AS country,
       ev.events_num AS events_number
  FROM COUNTRIES c
       INNER JOIN
       ev_cnt AS ev ON c.COUNTRY_ID = ev.id


En el código MQL5, la consulta compuesta se implementa de la siguiente manera:

//--- 2) group events number by country name using a subquery
::Print("\nGroup events number by country name using a subquery:\n");
string subquery=db_obj.SqlRequest();
string new_sql_request=::StringFormat("SELECT c.NAME AS country,"
                                      "ev.events_num AS events_number FROM COUNTRIES c "
                                      "JOIN(%s) AS ev "
                                      "ON c.COUNTRY_ID=ev.id", subquery);
if(!db_obj.Select(new_sql_request))
  {
   db_obj.Close();
   return;
  }
//--- print the SQL request
if(db_obj.PrintSqlRequest()<0)
   ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError());
db_obj.FinalizeSqlRequest();


Mientras que la expresión de la tabla (STE) se implementa de la forma siguiente:

//--- 3) group events number by country name using CTE
::Print("\nGroup events number by country name using CTE:\n");
new_sql_request=::StringFormat("WITH ev_cnt AS (%s)"
                               "SELECT c.NAME AS country,"
                               "ev.events_num AS events_number FROM COUNTRIES c "
                               "INNER JOIN ev_cnt AS ev ON c.COUNTRY_ID=ev.id", subquery);
if(!db_obj.Select(new_sql_request))
  {
   db_obj.Close();
   return;
  }
//--- print the SQL request
if(db_obj.PrintSqlRequest()<0)
   ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError());
db_obj.FinalizeSqlRequest();


Ambas opciones imprimirán los resultados de la consulta en el diario de registro:

sRequest1 (EURUSD,H1)    #| country        events_number
sRequest1 (EURUSD,H1)   --+-----------------------------
sRequest1 (EURUSD,H1)    1| Worldwide                  7 
sRequest1 (EURUSD,H1)    2| Australia                 85 
sRequest1 (EURUSD,H1)    3| Brazil                    55 
sRequest1 (EURUSD,H1)    4| Canada                    74 
sRequest1 (EURUSD,H1)    5| China                     40 
sRequest1 (EURUSD,H1)    6| France                    43 
sRequest1 (EURUSD,H1)    7| Germany                   62 
sRequest1 (EURUSD,H1)    8| Hong Kong                 26 
sRequest1 (EURUSD,H1)    9| India                     57 
sRequest1 (EURUSD,H1)   10| Italy                     52 
sRequest1 (EURUSD,H1)   11| Japan                    124 
sRequest1 (EURUSD,H1)   12| South Korea               36 
sRequest1 (EURUSD,H1)   13| Mexico                    47 
sRequest1 (EURUSD,H1)   14| New Zealand               82 
sRequest1 (EURUSD,H1)   15| Norway                    47 
sRequest1 (EURUSD,H1)   16| Singapore                 27 
sRequest1 (EURUSD,H1)   17| South Africa              54 
sRequest1 (EURUSD,H1)   18| Spain                     39 
sRequest1 (EURUSD,H1)   19| Sweden                    59 
sRequest1 (EURUSD,H1)   20| Switzerland               40 
sRequest1 (EURUSD,H1)   21| United Kingdom           115 
sRequest1 (EURUSD,H1)   22| United States            247 
sRequest1 (EURUSD,H1)   23| European Union            82 


Resulta fácil ver que el calendario se centra sobre todo en eventos estadounidenses: hay 247.

Vamos a complicar un poco la tarea añadiendo a la muestra una columna en la que contaremos cuántos eventos importantes se producen en un país concreto. El grado de importancia se definirá en la columna "IMPORTANCE". Solo seleccionaremos los eventos que tengan un valor "High".

Trabajaremos primero con la tabla "EVENTS". Aquí tendremos que crear 2 muestras. La primera muestra será un recuento del número de eventos por país. Esta tarea ya se ha ejecutado anteriormente. La segunda muestra será un recuento del número de eventos importantes por país. Por último, deberemos fusionar las dos muestras.

El código SQL de la consulta se representa de la forma siguiente:

SELECT evn.COUNTRY_ID AS id,
       COUNT(EVENT_ID) AS events_num,
       imp.high AS imp_events_num
  FROM EVENTS evn
       JOIN
       (
           SELECT COUNTRY_ID AS id,
                  COUNT(IMPORTANCE) AS high
             FROM EVENTS
            WHERE IMPORTANCE = 'High'
            GROUP BY COUNTRY_ID
       )
       AS imp ON evn.COUNTRY_ID = imp.id
 GROUP BY COUNTRY_ID


En cuanto a la implementación en MQL5, el código será como sigue:

//--- 5) important events - ids, events number and important events number
::Print("\nGroup events number and important events number by country id");
subquery=db_obj.SqlRequest();
string new_sql_request4=::StringFormat("SELECT ev.COUNTRY_ID AS id, COUNT(EVENT_ID) AS events_num,"
                                       "imp.high AS imp_events_num "
                                       "FROM EVENTS ev JOIN (%s) AS imp "
                                       "ON ev.COUNTRY_ID=imp.id GROUP BY COUNTRY_ID", subquery);
if(!db_obj.Select(new_sql_request4))
  {
   db_obj.Close();
   return;
  }
//--- print the SQL request
if(db_obj.PrintSqlRequest()<0)
   ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError());
db_obj.FinalizeSqlRequest();

Como resultado, obtendremos entradas en el diario de registro como esta:

sRequest1 (EURUSD,H1)   Group events number and important events number by country id:
sRequest1 (EURUSD,H1)   
sRequest1 (EURUSD,H1)    #|  id events_num imp_events_num
sRequest1 (EURUSD,H1)   --+------------------------------
sRequest1 (EURUSD,H1)    1|   0          7              2 
sRequest1 (EURUSD,H1)    2|  36         85              5 
sRequest1 (EURUSD,H1)    3|  76         55              2 
sRequest1 (EURUSD,H1)    4| 124         74             10 
sRequest1 (EURUSD,H1)    5| 156         40              5 
sRequest1 (EURUSD,H1)    6| 250         43              1 
sRequest1 (EURUSD,H1)    7| 276         62              3 
sRequest1 (EURUSD,H1)    8| 344         26              1 
sRequest1 (EURUSD,H1)    9| 356         57              2 
sRequest1 (EURUSD,H1)   10| 392        124              7 
sRequest1 (EURUSD,H1)   11| 410         36              2 
sRequest1 (EURUSD,H1)   12| 484         47              2 
sRequest1 (EURUSD,H1)   13| 554         82              8 
sRequest1 (EURUSD,H1)   14| 578         47              2 
sRequest1 (EURUSD,H1)   15| 702         27              1 
sRequest1 (EURUSD,H1)   16| 710         54              2 
sRequest1 (EURUSD,H1)   17| 752         59              1 
sRequest1 (EURUSD,H1)   18| 756         40              4 
sRequest1 (EURUSD,H1)   19| 826        115             13 
sRequest1 (EURUSD,H1)   20| 840        247             20 
sRequest1 (EURUSD,H1)   21| 999         82             11 


En la muestra final, solo quedará sustituir la columna "id" por "country".

Una vez más, crearemos una consulta compuesta. Aprovecharemos que algunas partes ya se han escrito antes. Al final de la muestra, clasificaremos los valores de la columna "imp_events_number" en orden descendente. La consulta compuesta tendrá el aspecto siguiente:

SELECT c.NAME AS country,
       ev.events_num AS events_number,
       ev.imp_events_num AS imp_events_number
  FROM COUNTRIES c
       JOIN
       (
           SELECT ev.COUNTRY_ID AS id,
                  COUNT(EVENT_ID) AS events_num,
                  imp.high AS imp_events_num
             FROM EVENTS ev
                  JOIN
                  (
                      SELECT COUNTRY_ID AS id,
                             COUNT(IMPORTANCE) AS high
                        FROM EVENTS
                       WHERE IMPORTANCE = 'High'
                       GROUP BY COUNTRY_ID
                  )
                  AS imp ON ev.COUNTRY_ID = imp.id
            GROUP BY COUNTRY_ID
       )
       AS ev ON c.COUNTRY_ID = ev.id
 ORDER BY imp_events_number DESC


En código MQL5, la consulta se implementará de la siguiente manera:

//--- 6) important events - countries, events number and important events number
::Print("\nGroup events number and important events number by country:\n");
subquery=db_obj.SqlRequest();
string new_sql_request5=::StringFormat("SELECT c.NAME AS country,"
                                       "ev.events_num AS events_number,"
                                       "ev.imp_events_num AS imp_events_number "
                                       "FROM COUNTRIES c "
                                       "JOIN(%s) AS ev "
                                       "ON c.COUNTRY_ID=ev.id "
                                       "ORDER BY imp_events_number DESC", subquery);
if(!db_obj.Select(new_sql_request5))
  {
   db_obj.Close();
   return;
  }
//--- print the SQL request
if(db_obj.PrintSqlRequest()<0)
   ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError());
db_obj.FinalizeSqlRequest();


Ahora, en el diario de registro, obtendremos la muestra que buscamos:

sRequest1 (EURUSD,H1)   Group events number and important events number by country:
sRequest1 (EURUSD,H1)   
sRequest1 (EURUSD,H1)    #| country        events_number imp_events_number
sRequest1 (EURUSD,H1)   --+-----------------------------------------------
sRequest1 (EURUSD,H1)    1| United States            247                20 
sRequest1 (EURUSD,H1)    2| United Kingdom           115                13 
sRequest1 (EURUSD,H1)    3| European Union            82                11 
sRequest1 (EURUSD,H1)    4| Canada                    74                10 
sRequest1 (EURUSD,H1)    5| New Zealand               82                 8 
sRequest1 (EURUSD,H1)    6| Japan                    124                 7 
sRequest1 (EURUSD,H1)    7| Australia                 85                 5 
sRequest1 (EURUSD,H1)    8| China                     40                 5 
sRequest1 (EURUSD,H1)    9| Switzerland               40                 4 
sRequest1 (EURUSD,H1)   10| Germany                   62                 3 
sRequest1 (EURUSD,H1)   11| Worldwide                  7                 2 
sRequest1 (EURUSD,H1)   12| Brazil                    55                 2 
sRequest1 (EURUSD,H1)   13| India                     57                 2 
sRequest1 (EURUSD,H1)   14| South Korea               36                 2 
sRequest1 (EURUSD,H1)   15| Mexico                    47                 2 
sRequest1 (EURUSD,H1)   16| Norway                    47                 2 
sRequest1 (EURUSD,H1)   17| South Africa              54                 2 
sRequest1 (EURUSD,H1)   18| France                    43                 1 
sRequest1 (EURUSD,H1)   19| Hong Kong                 26                 1 
sRequest1 (EURUSD,H1)   20| Singapore                 27                 1 
sRequest1 (EURUSD,H1)   21| Sweden                    59                 1 


Como se desprende de la muestra, Estados Unidos es el país con más eventos importantes: 20. En segundo lugar, tenemos a Gran Bretaña, con 13. En tercer lugar, vemos a la Unión Europea, con 11. Japón solo ocupa el sexto lugar, con 7.

Vamos a utilizar las consultas para encontrar los países que no tienen ningún evento importante. Para ello, deberemos hallar la diferencia entre dos muestras. La primera selección incluirá todos los países de la tabla "COUNTRIES", mientras que la segunda muestra incluirá la columna con los países de la consulta compuesta anterior.

El código SQL será entonces el siguiente:

SELECT NAME
  FROM COUNTRIES
EXCEPT
SELECT country
  FROM (
           SELECT c.NAME AS country,
                  ev.events_num AS events_number,
                  ev.imp_events_num AS imp_events_number
             FROM COUNTRIES c
                  JOIN
                  (
                      SELECT ev.COUNTRY_ID AS id,
                             COUNT(EVENT_ID) AS events_num,
                             imp.high AS imp_events_num
                        FROM EVENTS ev
                             JOIN
                             (
                                 SELECT COUNTRY_ID AS id,
                                        COUNT(IMPORTANCE) AS high
                                   FROM EVENTS
                                  WHERE IMPORTANCE = 'High'
                                  GROUP BY COUNTRY_ID
                             )
                             AS imp ON ev.COUNTRY_ID = imp.id
                       GROUP BY COUNTRY_ID
                  )
                  AS ev ON c.COUNTRY_ID = ev.id
       )


El código MQL5 parecerá más sencillo, porque aprovecharemos que la consulta anterior se ha convertido en nuestra nueva subconsulta.

//--- 7) countries having no important events
::Print("\nCountries having no important events:\n");
string last_request=db_obj.SqlRequest();
string new_sql_request6=::StringFormat("SELECT NAME FROM COUNTRIES "
                                       "EXCEPT SELECT country FROM (%s)", last_request);
if(!db_obj.Select(new_sql_request6))
  {
   db_obj.Close();
   return;
  }
//--- print the SQL request
if(db_obj.PrintSqlRequest()<0)
   ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError());
db_obj.FinalizeSqlRequest();


Cuando el código esté completo, obtendremos estas entradas en el diario de registro:

sRequest1 (EURUSD,H1)   Countries having no important events:
sRequest1 (EURUSD,H1)   
sRequest1 (EURUSD,H1)   #| NAME 
sRequest1 (EURUSD,H1)   -+------
sRequest1 (EURUSD,H1)   1| Italy 
sRequest1 (EURUSD,H1)   2| Spain 


Es decir, de todos los países, solo Italia y España no tienen eventos importantes. Las consultas sobre eventos de países en MQL5 se realizaban en el script sRequest1.mq5.


3.2.2 Muestra de los valores del PIB por países

En este ejemplo, consultaremos la base de datos para intentar obtener una muestra de los valores del PIB de distintos países. Como valor del PIB, tomaremos "Producto Interior Bruto (PIB) t/t" (para el 3er trimestre).

Habrá varias muestras, por lo que la consulta será compuesta.

En primer lugar, vamos a ver qué economías disponen de un indicador trimestral del PIB.

El código SQL se representa de la forma siguiente:

SELECT COUNTRY_ID,
       EVENT_ID
  FROM EVENTS
 WHERE (NAME LIKE 'GDP q/q' AND 
        SECTOR = 'Gross Domestic Product')


La implementación en MQL5 tiene este aspecto (script sRequest2.mq5):

//--- 1) countries by id where the indicator '%GDP q/q%' exists
string col_names[]= {"COUNTRY_ID", "EVENT_ID"};
string where_condition="(NAME LIKE 'GDP q/q' AND SECTOR='Gross Domestic Product')";
if(!db_obj.SelectFromWhere(col_names, where_condition))
  {
   db_obj.Close();
   return;
  }
::Print("\nCountries by id where the indicator 'GDP q/q' exists:\n");
//--- print the SQL request
if(db_obj.PrintSqlRequest()<0)
   ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError());
db_obj.FinalizeSqlRequest();


Y la impresión del diario de registro tras realizar la consulta:

sRequest2 (EURUSD,H1)   Countries by id where the indicator 'GDP q/q' exists:
sRequest2 (EURUSD,H1)   
sRequest2 (EURUSD,H1)    #| COUNTRY_ID  EVENT_ID
sRequest2 (EURUSD,H1)   --+---------------------
sRequest2 (EURUSD,H1)    1|        554 554010024 
sRequest2 (EURUSD,H1)    2|        999 999030016 
sRequest2 (EURUSD,H1)    3|        392 392010001 
sRequest2 (EURUSD,H1)    4|        124 124010022 
sRequest2 (EURUSD,H1)    5|         36  36010019 
sRequest2 (EURUSD,H1)    6|        156 156010004 
sRequest2 (EURUSD,H1)    7|        380 380010020 
sRequest2 (EURUSD,H1)    8|        702 702010004 
sRequest2 (EURUSD,H1)    9|        276 276010008 
sRequest2 (EURUSD,H1)   10|        250 250010005 
sRequest2 (EURUSD,H1)   11|         76  76010010 
sRequest2 (EURUSD,H1)   12|        484 484020016 
sRequest2 (EURUSD,H1)   13|        710 710060009 
sRequest2 (EURUSD,H1)   14|        344 344020002 
sRequest2 (EURUSD,H1)   15|        578 578020012 
sRequest2 (EURUSD,H1)   16|        840 840010007 
sRequest2 (EURUSD,H1)   17|        826 826010037 
sRequest2 (EURUSD,H1)   18|        756 756040001 
sRequest2 (EURUSD,H1)   19|        410 410010011 
sRequest2 (EURUSD,H1)   20|        724 724010005 
sRequest2 (EURUSD,H1)   21|        752 752010019 


Veremos que el indicador buscado existe en 21 países. Este indicador no se usa en la India ni a escala mundial.

Ahora deberemos obtener la muestra de los valores del indicador del tercer trimestre y vincularla a la primera muestra según el ID de evento.

La consulta SQL tendrá el siguiente aspecto:

SELECT evs.COUNTRY_ID AS country_id,
       evals.EVENT_ID AS event_id,
       evals.VALUE_ID AS value_id,
       evals.PERIOD AS period,
       evals.TIME AS time,
       evals.ACTUAL AS actual
  FROM EVENT_VALUES evals
       JOIN
       (
           SELECT COUNTRY_ID,
                  EVENT_ID
             FROM EVENTS
            WHERE (NAME LIKE 'GDP q/q' AND 
                   SECTOR = 'Gross Domestic Product') 
       )
       AS evs ON evals.event_id = evs.EVENT_ID
WHERE (period = '2022.07.01 00:00' )


En cuanto al código MQL5, la consulta compuesta se implementará del siguiente modo:

//--- 2)  'GDP y/y' event and last values
string subquery=db_obj.SqlRequest();
string new_sql_request1=::StringFormat("SELECT evs.COUNTRY_ID AS country_id,"
                                       "evals.EVENT_ID AS event_id,"
                                       "evals.VALUE_ID AS value_id,"
                                       "evals.PERIOD AS period,"
                                       "evals.TIME AS time,"
                                       "evals.ACTUAL AS actual "
                                       "FROM EVENT_VALUES evals "
                                       "JOIN(%s) AS evs ON evals.event_id = evs.event_id "
                                       " WHERE (period = \'2022.07.01 00:00\')", subquery);
if(!db_obj.Select(new_sql_request1))
  {
   db_obj.Close();
   return;
  }
::Print("\n'GDP y/y' event and last values:\n");
//--- print the SQL request
if(db_obj.PrintSqlRequest()<0)
   ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError());
db_obj.FinalizeSqlRequest();


Tras su ejecución, el diario de registro mostrará líneas como ésta:

sRequest2 (EURUSD,H1)   'GDP q/q' event and last values:
sRequest2 (EURUSD,H1)   
sRequest2 (EURUSD,H1)    #| country_id  event_id value_id period           time             actual
sRequest2 (EURUSD,H1)   --+-----------------------------------------------------------------------
sRequest2 (EURUSD,H1)    1|        554 554010024   168293 2022.07.01 00:00 2022.12.14 23:45    2.0 
sRequest2 (EURUSD,H1)    2|        999 999030016   158836 2022.07.01 00:00 2022.10.31 12:00    0.2 
sRequest2 (EURUSD,H1)    3|        999 999030016   158837 2022.07.01 00:00 2022.11.15 12:00    0.2 
sRequest2 (EURUSD,H1)    4|        999 999030016   158838 2022.07.01 00:00 2022.12.07 12:00    0.3 
sRequest2 (EURUSD,H1)    5|        392 392010001   165181 2022.07.01 00:00 2022.11.15 01:50   -0.3 
sRequest2 (EURUSD,H1)    6|        392 392010001   165182 2022.07.01 00:00 2022.12.08 01:50   -0.2 
sRequest2 (EURUSD,H1)    7|        124 124010022   161963 2022.07.01 00:00 2022.11.29 15:30    0.7 
sRequest2 (EURUSD,H1)    8|         36  36010019   173679 2022.07.01 00:00 2022.12.07 02:30    0.6 
sRequest2 (EURUSD,H1)    9|        156 156010004   172459 2022.07.01 00:00 2022.10.24 04:00    3.9 
sRequest2 (EURUSD,H1)   10|        380 380010020   162296 2022.07.01 00:00 2022.10.31 11:00    0.5 
sRequest2 (EURUSD,H1)   11|        380 380010020   162297 2022.07.01 00:00 2022.11.30 11:00    0.5 
sRequest2 (EURUSD,H1)   12|        702 702010004   167581 2022.07.01 00:00 2022.10.14 02:00    1.5 
sRequest2 (EURUSD,H1)   13|        702 702010004   174527 2022.07.01 00:00 2022.11.23 02:00    1.1 
sRequest2 (EURUSD,H1)   14|        276 276010008   172410 2022.07.01 00:00 2022.10.28 10:00    0.3 
sRequest2 (EURUSD,H1)   15|        276 276010008   157759 2022.07.01 00:00 2022.11.25 09:00    0.4 
sRequest2 (EURUSD,H1)   16|        250 250010005   169062 2022.07.01 00:00 2022.10.28 07:30    0.2 
sRequest2 (EURUSD,H1)   17|        250 250010005   169389 2022.07.01 00:00 2022.11.30 09:45    0.2 
sRequest2 (EURUSD,H1)   18|         76  76010010   173825 2022.07.01 00:00 2022.12.01 14:00    0.4 
sRequest2 (EURUSD,H1)   19|        484 484020016   166108 2022.07.01 00:00 2022.10.31 14:00    1.0 
sRequest2 (EURUSD,H1)   20|        484 484020016   166109 2022.07.01 00:00 2022.11.25 14:00    0.9 
sRequest2 (EURUSD,H1)   21|        710 710060009   175234 2022.07.01 00:00 2022.12.06 11:30    1.6 
sRequest2 (EURUSD,H1)   22|        344 344020002   155337 2022.07.01 00:00 2022.10.31 10:30   -2.6 
sRequest2 (EURUSD,H1)   23|        344 344020002   155338 2022.07.01 00:00 2022.11.11 10:30   -2.6 
sRequest2 (EURUSD,H1)   24|        578 578020012   172320 2022.07.01 00:00 2022.11.18 09:00    1.5 
sRequest2 (EURUSD,H1)   25|        840 840010007   163417 2022.07.01 00:00 2022.10.27 14:30    2.6 
sRequest2 (EURUSD,H1)   26|        840 840010007   163418 2022.07.01 00:00 2022.11.30 15:30    2.9 
sRequest2 (EURUSD,H1)   27|        840 840010007   163419 2022.07.01 00:00 2022.12.22 15:30    3.2 
sRequest2 (EURUSD,H1)   28|        826 826010037   157174 2022.07.01 00:00 2022.11.11 09:00   -0.2 
sRequest2 (EURUSD,H1)   29|        826 826010037   157175 2022.07.01 00:00 2022.12.22 09:00   -0.3 
sRequest2 (EURUSD,H1)   30|        756 756040001   159276 2022.07.01 00:00 2022.11.29 10:00    0.2 
sRequest2 (EURUSD,H1)   31|        410 410010011   161626 2022.07.01 00:00 2022.10.27 01:00    0.3 
sRequest2 (EURUSD,H1)   32|        410 410010011   161627 2022.07.01 00:00 2022.12.01 01:00    0.3 
sRequest2 (EURUSD,H1)   33|        724 724010005   159814 2022.07.01 00:00 2022.10.28 09:00    0.2 
sRequest2 (EURUSD,H1)   34|        724 724010005   159815 2022.07.01 00:00 2022.12.23 10:00    0.1 
sRequest2 (EURUSD,H1)   35|        752 752010019   170359 2022.07.01 00:00 2022.10.28 08:00    0.7 
sRequest2 (EURUSD,H1)   36|        752 752010019   171381 2022.07.01 00:00 2022.11.29 09:00    0.6 


Resulta fácil ver que hay varios valores en la muestra para algunos eventos con el mismo event_id. Por ejemplo, las entradas 2-4 hacen referencia al parámetro de la UE. Lo que ocurre es que el PIB se ha estimado en varias lecturas, de ahí que haya varios valores para el indicador. Como resultado, tenemos 36 entradas en la muestra resultante, una cifra claramente superior al número de países para los que se calcula el indicador.

Si queremos muestrear solo los últimos valores de un evento determinado, la consulta deberá incluir la opción de agrupación y un filtro para los resultados agrupados. Entonces obtendremos esta consulta SQL compuesta:

SELECT evs.COUNTRY_ID AS country_id,
       evals.EVENT_ID AS event_id,
       evals.VALUE_ID AS value_id,
       evals.PERIOD AS period,
       evals.TIME AS time,
       evals.ACTUAL AS actual
  FROM EVENT_VALUES evals
       JOIN
       (
           SELECT COUNTRY_ID,
                  EVENT_ID
             FROM EVENTS
            WHERE (NAME LIKE 'GDP q/q' AND 
                   SECTOR = 'Gross Domestic Product') 
       )
       AS evs ON evals.event_id = evs.EVENT_ID
WHERE (period = '2022.07.01 00:00' )
GROUP BY evals.event_id 
HAVING MAX(value_id)


Las entradas se agruparán según la columna (campo) "event_id". Si hay más de una entrada, se utilizará como principal la que tenga el valor más alto en la columna (campo) "value_id". Así, por ejemplo, solo se seleccionará una de las tres entradas para la UE:

country_id event_id value_id period time actual
999 999030016 158838 2022.07.01 00:00 2022.12.07 12:00 0.3


Como resultado, aparecerán entradas como éstas en el diario de registro:

sRequest2 (EURUSD,H1)   'GDP q/q' event and grouped last values:
sRequest2 (EURUSD,H1)   
sRequest2 (EURUSD,H1)    #| country_id  event_id value_id period           time             actual
sRequest2 (EURUSD,H1)   --+-----------------------------------------------------------------------
sRequest2 (EURUSD,H1)    1|         36  36010019   173679 2022.07.01 00:00 2022.12.07 02:30    0.6 
sRequest2 (EURUSD,H1)    2|         76  76010010   173825 2022.07.01 00:00 2022.12.01 14:00    0.4 
sRequest2 (EURUSD,H1)    3|        124 124010022   161963 2022.07.01 00:00 2022.11.29 15:30    0.7 
sRequest2 (EURUSD,H1)    4|        156 156010004   172459 2022.07.01 00:00 2022.10.24 04:00    3.9 
sRequest2 (EURUSD,H1)    5|        250 250010005   169389 2022.07.01 00:00 2022.11.30 09:45    0.2 
sRequest2 (EURUSD,H1)    6|        276 276010008   172410 2022.07.01 00:00 2022.10.28 10:00    0.3 
sRequest2 (EURUSD,H1)    7|        344 344020002   155338 2022.07.01 00:00 2022.11.11 10:30   -2.6 
sRequest2 (EURUSD,H1)    8|        380 380010020   162297 2022.07.01 00:00 2022.11.30 11:00    0.5 
sRequest2 (EURUSD,H1)    9|        392 392010001   165182 2022.07.01 00:00 2022.12.08 01:50   -0.2 
sRequest2 (EURUSD,H1)   10|        410 410010011   161627 2022.07.01 00:00 2022.12.01 01:00    0.3 
sRequest2 (EURUSD,H1)   11|        484 484020016   166109 2022.07.01 00:00 2022.11.25 14:00    0.9 
sRequest2 (EURUSD,H1)   12|        554 554010024   168293 2022.07.01 00:00 2022.12.14 23:45    2.0 
sRequest2 (EURUSD,H1)   13|        578 578020012   172320 2022.07.01 00:00 2022.11.18 09:00    1.5 
sRequest2 (EURUSD,H1)   14|        702 702010004   174527 2022.07.01 00:00 2022.11.23 02:00    1.1 
sRequest2 (EURUSD,H1)   15|        710 710060009   175234 2022.07.01 00:00 2022.12.06 11:30    1.6 
sRequest2 (EURUSD,H1)   16|        724 724010005   159815 2022.07.01 00:00 2022.12.23 10:00    0.1 
sRequest2 (EURUSD,H1)   17|        752 752010019   171381 2022.07.01 00:00 2022.11.29 09:00    0.6 
sRequest2 (EURUSD,H1)   18|        756 756040001   159276 2022.07.01 00:00 2022.11.29 10:00    0.2 
sRequest2 (EURUSD,H1)   19|        826 826010037   157175 2022.07.01 00:00 2022.12.22 09:00   -0.3 
sRequest2 (EURUSD,H1)   20|        840 840010007   163419 2022.07.01 00:00 2022.12.22 15:30    3.2 
sRequest2 (EURUSD,H1)   21|        999 999030016   158838 2022.07.01 00:00 2022.12.07 12:00    0.3 


Ahora tenemos 21 entradas en la muestra. El toque final será sustituir el código del país por su nombre. Para ello, cambiaremos la consulta SLQ anterior por la siguiente:

SELECT c.NAME AS country,
       ev_evals.event_id AS event_id,
       ev_evals.value_id AS value_id,
       ev_evals.period AS period,
       ev_evals.TIME AS time,
       ev_evals.ACTUAL AS actual
  FROM COUNTRIES c
       JOIN
       (
           SELECT evs.COUNTRY_ID AS country_id,
                  evals.EVENT_ID AS event_id,
                  evals.VALUE_ID AS value_id,
                  evals.PERIOD AS period,
                  evals.TIME AS time,
                  evals.ACTUAL AS actual
             FROM EVENT_VALUES evals
                  JOIN
                  (
                      SELECT COUNTRY_ID,
                             EVENT_ID
                        FROM EVENTS
                       WHERE (NAME LIKE 'GDP q/q' AND 
                              SECTOR = 'Gross Domestic Product') 
                  )
                  AS evs ON evals.event_id = evs.EVENT_ID
            WHERE (period = '2022.07.01 00:00') 
            GROUP BY evals.event_id
           HAVING MAX(value_id) 
       )
       AS ev_evals ON c.COUNTRY_ID = ev_evals.country_id


De paso, implementaremos esta consulta compuesta en MQL5:

//--- 4)  'GDP q/q' event and grouped last values with country names
subquery=db_obj.SqlRequest();
string new_sql_request3=::StringFormat("SELECT c.NAME AS country,"
                                       "ev_evals.event_id AS event_id,"
                                       "ev_evals.value_id AS value_id,"
                                       "ev_evals.period AS period,"
                                       "ev_evals.TIME AS time,"
                                       "ev_evals.ACTUAL AS actual "
                                       "FROM COUNTRIES c JOIN (%s) "
                                       "AS ev_evals ON c.COUNTRY_ID = ev_evals.country_id",
                                       subquery);
if(!db_obj.Select(new_sql_request3))
  {
   db_obj.Close();
   return;
  }
::Print("\n'GDP q/q' event and grouped last values with country names:\n");
//--- print the SQL request
if(db_obj.PrintSqlRequest()<0)
   ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError());
db_obj.FinalizeSqlRequest();


La muestra que buscamos estará impresa en el diario de registro:

sRequest2 (EURUSD,H1)   'GDP q/q' event and grouped last values with country names:
sRequest2 (EURUSD,H1)   
sRequest2 (EURUSD,H1)    #| country         event_id value_id period           time             actual
sRequest2 (EURUSD,H1)   --+---------------------------------------------------------------------------
sRequest2 (EURUSD,H1)    1| Australia       36010019   173679 2022.07.01 00:00 2022.12.07 02:30    0.6 
sRequest2 (EURUSD,H1)    2| Brazil          76010010   173825 2022.07.01 00:00 2022.12.01 14:00    0.4 
sRequest2 (EURUSD,H1)    3| Canada         124010022   161963 2022.07.01 00:00 2022.11.29 15:30    0.7 
sRequest2 (EURUSD,H1)    4| China          156010004   172459 2022.07.01 00:00 2022.10.24 04:00    3.9 
sRequest2 (EURUSD,H1)    5| France         250010005   169389 2022.07.01 00:00 2022.11.30 09:45    0.2 
sRequest2 (EURUSD,H1)    6| Germany        276010008   172410 2022.07.01 00:00 2022.10.28 10:00    0.3 
sRequest2 (EURUSD,H1)    7| Hong Kong      344020002   155338 2022.07.01 00:00 2022.11.11 10:30   -2.6 
sRequest2 (EURUSD,H1)    8| Italy          380010020   162297 2022.07.01 00:00 2022.11.30 11:00    0.5 
sRequest2 (EURUSD,H1)    9| Japan          392010001   165182 2022.07.01 00:00 2022.12.08 01:50   -0.2 
sRequest2 (EURUSD,H1)   10| South Korea    410010011   161627 2022.07.01 00:00 2022.12.01 01:00    0.3 
sRequest2 (EURUSD,H1)   11| Mexico         484020016   166109 2022.07.01 00:00 2022.11.25 14:00    0.9 
sRequest2 (EURUSD,H1)   12| New Zealand    554010024   168293 2022.07.01 00:00 2022.12.14 23:45    2.0 
sRequest2 (EURUSD,H1)   13| Norway         578020012   172320 2022.07.01 00:00 2022.11.18 09:00    1.5 
sRequest2 (EURUSD,H1)   14| Singapore      702010004   174527 2022.07.01 00:00 2022.11.23 02:00    1.1 
sRequest2 (EURUSD,H1)   15| South Africa   710060009   175234 2022.07.01 00:00 2022.12.06 11:30    1.6 
sRequest2 (EURUSD,H1)   16| Spain          724010005   159815 2022.07.01 00:00 2022.12.23 10:00    0.1 
sRequest2 (EURUSD,H1)   17| Sweden         752010019   171381 2022.07.01 00:00 2022.11.29 09:00    0.6 
sRequest2 (EURUSD,H1)   18| Switzerland    756040001   159276 2022.07.01 00:00 2022.11.29 10:00    0.2 
sRequest2 (EURUSD,H1)   19| United Kingdom 826010037   157175 2022.07.01 00:00 2022.12.22 09:00   -0.3 
sRequest2 (EURUSD,H1)   20| United States  840010007   163419 2022.07.01 00:00 2022.12.22 15:30    3.2 
sRequest2 (EURUSD,H1)   21| European Union 999030016   158838 2022.07.01 00:00 2022.12.07 12:00    0.3 


Querríamos señalar que, aunque la tarea se ha resuelto con varios enfoques, la posibilidad de incorporar una consulta a otra ha facilitado mucho las cosas.


Conclusión

Espero que este artículo resulte de interés para los tráders y desarrolladores que utilizan datos macroeconómicos en sus estrategias. También me atrevería a sugerir que probablemente no existan macroindicadores en los que basar una buena estrategia. Pero como complemento a los datos originales de la red neuronal, por ejemplo, estos indicadores pueden ser de utilidad. 

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

Archivos adjuntos |
CalendarDB.zip (52.66 KB)
Teoría de categorías en MQL5 (Parte 2) Teoría de categorías en MQL5 (Parte 2)
La teoría de categorías es una rama diversa y en expansión de las matemáticas, relativamente inexplorada aún en la comunidad MQL5. Esta serie de artículos tiene como objetivo destacar algunos de sus conceptos para crear una biblioteca abierta y seguir utilizando esta maravillosa sección para crear estrategias comerciales.
Desarrollando una DLL experimental con soporte multihilo en C++ para MetaTrader 5 en Linux Desarrollando una DLL experimental con soporte multihilo en C++ para MetaTrader 5 en Linux
En este artículo, describiremos el proceso de desarrollo de la plataforma MetaTrader 5 exclusivamente en Linux. El producto final funcionará a la perfección tanto en Windows como en Linux. Asimismo, aprenderemos sobre Wine y Mingw, herramientas importantes para el desarrollo multiplataforma. Mingw ofrece transmisión de flujo (POSIX y Win32), lo que debe tenerse en cuenta a la hora de elegir la herramienta adecuada. A continuación crearemos una DLL para probar el concepto; luego la usaremos en el código MQL5 y compararemos el rendimiento de ambas implementaciones de los hilos. Este artículo pretende ser un punto de partida para experimentos propios. Después de leer este artículo, el lector será capaz de crear herramientas para MetaTrader en Linux.
Probando y optimizando estrategias de opciones binarias en MetaTrader 5 Probando y optimizando estrategias de opciones binarias en MetaTrader 5
Probando y optimizando estrategias de opciones binarias en MetaTrader 5
Algoritmos de optimización de la población: Algoritmo de forrajeo bacteriano (Bacterial Foraging Optimisation — BFO) Algoritmos de optimización de la población: Algoritmo de forrajeo bacteriano (Bacterial Foraging Optimisation — BFO)
La estrategia de búsqueda de alimento de la bacteria E.coli inspiró a los científicos para crear el algoritmo de optimización BFO. El algoritmo contiene ideas originales y enfoques prometedores para la optimización y merece ser investigado en profundidad.