English Русский 中文 Español Deutsch 日本語
preview
Receitas MQL5 — Banco de dados de eventos macroeconômicos

Receitas MQL5 — Banco de dados de eventos macroeconômicos

MetaTrader 5Exemplos | 12 maio 2023, 16:12
410 0
Denis Kirichenko
Denis Kirichenko

Introdução

Este artigo se concentrará em como agrupar e gerenciar dados que descrevem eventos macroeconômicos do calendário.

Quer queira quer não, no mundo moderno, onde a quantidade de informações é imensa, é inevitável lidar com big data ao analisar eventos. Embora o artigo se foque principalmente na organização e estruturação dos dados, é evidente que a forma como eles são manipulados desempenha um papel crucial na transformação desses dados em informações úteis.

Para resolver as tarefas propostas, utilizaremos o SQLite como ferramenta. É importante ressaltar que o suporte para trabalhar diretamente com bancos de dados SQLite no MQL5 foi adicionado na compilação 2265, em 6 de dezembro de 2019. Isso elimina a necessidade de utilizar conectores adicionais, como mencionado no artigo "SQL e MQL5: Trabalhando com banco de dados SQLite"..


1. Documentação e material adicional

Vamos dar uma olhada rápida na Documentação em termos de trabalho com bancos de dados. O desenvolvedor proporciona 26 recursos nativos:

  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().

Fornece também um bloco de funções estatísticas e um bloco de funções matemáticas, que foram adicionados recentemente. Assim, o ponto de partida para começar a estudar essa funcionalidade pode ser o artigo SQLite: trabalho nativo com bancos de dados SQL em MQL5.


2. Classe de banco de dados CDatabase

Para facilitar o trabalho com bancos de dados, criamos a classe CDatabase. Primeiro, descrevemos como se compõe essa classe. Em seguida, verificamos seu funcionamento com exemplos.

A classe CDatabase inclui o seguinte:

  • m_name - nome do arquivo de banco de dados (com extensão);
  • m_handle - identificador de banco de dados;
  • m_flags - combinação de sinalizadores;
  • m_table_names - nomes de tabelas;
  • m_curr_table_name – nome da tabela atual;
  • m_sql_request_ha - identificador da última consulta SQL;
  • m_sql_request - última consulta SQL.

Quanto aos métodos, são divididos em vários grupos:

  1. Métodos que incluem funções nativas para trabalhar com bancos de dados (funções API MQL5);
  2. Métodos para trabalhar com tabelas;
  3. Métodos para trabalhar com consultas;
  4. Métodos para trabalhar com visualizações;
  5. Métodos para obter valores dos atributos (métodos get).

Gostaria de fazer a seguinte observação. O SQLite tem muitas formas de consulta, que variam de simples a complexas. Não foi nossa intenção criar um método separado na classe CDatabase para cada formulário.  Se não houver um método para uma determinada consulta em uma classe, você poderá usar o método de propósito geral CDatabase::Select() para gerá-la.

 

Vejamos agora exemplos de como você pode usar os recursos da classe CDatabase.


2.1 Criando um banco de dados

Vamos criar nosso primeiro banco de dados de calendário usando o script 1_create_calendar_db.mq5.  O script terá apenas algumas linhas 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();
  }
//+------------------------------------------------------------------+

Depois de executar o script, veremos que o arquivo de banco de dados test_calendar_db.sqlite apareceu na pasta %MQL5\Files\Databases (Fig.1).


Arquivo de banco de dados test_calendar_db.sqlite

Fig.1 Arquivo de banco de dados test_calendar_db.sqlite


Se abrirmos depois este arquivo no editor de código, veremos, por sua vez, que o banco de dados está vazio (Fig. 2).


Banco de dados test_calendar_db

Fig.2 Banco de dados test_calendar_db


2.2 Criando uma tabela

Vamos tentar preencher o banco de dados. Para isso, vamos criar uma tabela COUNTRIES com uma lista de países cujos eventos de calendário serão posteriormente processados por nossas consultas. O script 2_create_countries_table.mq5 fará o trabalho.

//--- 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();
   }
//+------------------------------------------------------------------+

Depois de executar o script, é possível ver que a tabela COUNTRIES aparece no banco de dados (Fig. 3).


Tabela COUNTRIES vazia

Fig.3 Tabela COUNTRIES vazia


2.3 Preenchendo uma tabela

Vamos preencher uma nova tabela com dados. Para fazer isso, usaremos os recursos da classe CiCalendarInfo. Para saber mais sobre a classe, consulte o artigo Receitas MQL5 - Calendário econômico. A tarefa será realizada diretamente pelo 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();
   }
//+------------------------------------------------------------------+

Vamos imprimir os dados da tabela COUNTRIES no log.

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      


No MetaEditor, a tabela fica assim (Fig.4).

Tabela COUNTRIES preenchida

Fig.4 Tabela COUNTRIES preenchida



2.4 Selecionando algumas colunas da tabela

Vamos trabalhar com os dados da tabela COUNTRIES. Digamos que queremos selecionar as seguintes colunas:

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

Vamos criar uma consulta SQL usando o script 4_select_some_columns.mq5 da seguinte forma:

//--- 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();
   }
//+------------------------------------------------------------------+


Quando imprimimos a consulta, obtemos:

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, a amostragem foi feita sem nenhuma classificação.


2.5 Selecionando algumas colunas classificadas

Vamos tentar classificar os dados na tabela pela coluna "COUNTRY_ID". Essa consulta tem essa implementação no 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();
   }
//+------------------------------------------------------------------+


O resultado da consulta aparece no log:

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      

O script funciona corretamente, pois a coluna "COUNTRY_ID" começa em 0 e termina em 999.


2.6 Selecionando resultados agrupados de uma coluna da tabela

Agora, usando o script 6_select_some_grouped_columns.mq5, tentaremos obter nomes de países agrupados por continente. A ideia é obter, para cada linha de um continente, o número de países incluídos nele. Os países são selecionados na coluna “NAME”. Depois de executar o script, as seguintes linhas aparecem no log:

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 


O continente "Europe" tem o maior número de países, com 9, enquanto os continentes "Africa" e "South America" têm apenas 1 cada. E o mundo inteiro se juntou a eles - "World".


2.7 Selecionando valores exclusivos para uma coluna da tabela

Agora, usando o script 7_select_distinct_columns.mq5, vamos coletar valores únicos na coluna "CURRENCY". Existem países onde é usada a mesma moeda. Para eliminar repetições, executamos este script e obtemos no log:

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      

Assim, o calendário possui eventos para um total de 18 moedas e um grupo de eventos que se aplica a todas elas.

É fácil perceber que os métodos para selecionar resultados agrupados e selecionar valores únicos possuem semelhanças. Vamos demonstrar isso com um exemplo.

O script 8_compare_ grouped_and_distinct_columns.mq5 imprimirá os seguintes resultados no log:

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             


Os métodos retornaram os mesmos resultados porque, no primeiro método, definimos a coluna "CONTINENT" como a coluna de agrupamento (campo). É interessante notar que o primeiro método também classificou nossa amostra.


2.8 Selecionando valores únicos ordenados de uma coluna da tabela

Os valores na coluna "CURRENCY" não foram exibidos de forma ordenada pelo script 7_select_distinct_columns.mq5. Vamos fazer a seleção já ordenada (script 9_select_sorted_distinct_columns.mq5). A coluna "COUNTRY_ID" será o critério de classificação. Como resultado do trabalho no log, obtemos:

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      


Agora todas as moedas estão classificadas. E, por padrão, a classificação está em ordem crescente.


2.9 Selecionando algumas colunas da tabela por condição

Anteriormente, já criamos uma consulta SQL para selecionar as colunas de uma tabela. Agora vamos fazer com que possamos obter as colunas quando alguma condição for atendida. Suponhamos que você queira selecionar países cujo ID seja igual ou maior que 392 e igual ou menor que 840. Esta tarefa é resolvida pelo script 10_select_some_columns_where.mq5.

Após executar o script, veremos no log:

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      


Ou seja, a amostra começa com o código do país, que é 392, e termina com o código 840. 


2.10 Selecionando algumas colunas de tabela classificadas por condição

Vamos complicar o problema anterior. Vamos adicionar um critério de classificação à amostra (pertença do país ao continente). A tarefa atual é resolvida no script 11_select_some_sorted_columns_where.mq5. Depois de executá-lo, veremos as seguintes linhas no log:

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, o país "South Africa" ocupa o primeiro lugar na amostra, porque o continente "Africa" vem em primeiro lugar na lista de continentes.


2.11 Atualizando algumas colunas da tabela por condição

Imaginemos que nos deparamos com a tarefa de atualizar as linhas nas colunas selecionadas. E devemos fazer isso, tendo previamente cumprido alguma condição.

Vamos pegar os países asiáticos e redefinir os valores para eles nas colunas "CURRENCY", "CURRENCY_SYMBOL". Esta tarefa é executada pelo script 12_update_some_columns.mq5.

Após sua execução, obtemos a seguinte tabela:

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 Substituindo e adicionando algumas linhas à tabela

Vamos continuar com as tabelas. Agora tentamos substituir algumas linhas na tabela selecionada.

Suponhamos que para o país “Mexico” na coluna "CURRENCY_SYMBOL" precisemos substituir o símbolo atual "Mex$" por "Peso mexicano". Vamos confiar esta tarefa ao script 13_replace_some_rows.mq5.

Na versão atual da tabela COUNTRIES, México tem a seguinte entrada:

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


mexico


Para substituir esta linha na tabela, precisamos especificar algum valor exclusivo para a linha selecionada. Caso contrário, o SQLite não entenderá o que queremos substituir.

Vamos assumir que este valor será o nome do país (coluna "NAME"). Então, no código, a função de substituição será representada da seguinte forma:

//--- 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;
  }


Ao executar o script, obtemos o seguinte erro:

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


Obviamente, a restrição NOT NULL é violada. Isso acontece porque, inicialmente, ao criar a tabela, foi especificado que a coluna COUNTRY_ID não pode conter um valor nulo. Portanto, é necessário adicionar um valor para esta coluna. E para não ficar com uma linha meio vazia, vamos somar valores para todas as colunas.

//--- 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;
  }

Agora o script funcionará perfeitamente. Obtemos as seguintes entradas no log:

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   


Vale a pena notar que, se não houvesse nenhuma linha contendo dados sobre o México, essa linha seria simplesmente adicionada. Ou seja, a operação de substituição também é uma operação de adição de linha de tabela.


2.13 Excluindo algumas linhas da tabela

Agora vamos ver como podemos encurtar as linhas da tabela em vez de expandi-las. Para isso, vamos criar o script 14_delete_some_rows.mq5, que irá, mediante solicitação, excluir as linhas da tabela selecionada relacionadas à Ásia.

Depois de executar o script, imprimimos a tabela final:

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         


Nenhuma string relacionada ao continente da Ásia foi encontrada.


2.14 Adicionando colunas à tabela

As operações com tabelas também incluem uma tarefa bastante comum, que é adicionar novas colunas.

Então, suponhamos que precisamos expandir nossa tabela COUNTRIES e adicionar uma coluna contendo o número de eventos macroeconômicos que se enquadram no calendário.

Vamos atribuir essa tarefa ao script 15_add_new_column.mq5.

Após executar o script, verificamos a tabela (Fig. 5). Tem uma nova coluna - "EVENTS_NUM".


Nova coluna “EVENTS_NUM” na tabela COUNTRIES

Fig.5 Nova coluna “EVENTS_NUM” na tabela COUNTRIES


2.15 Renomeando colunas em uma tabela

Se for necessário renomear uma coluna na tabela, usaremos o método CDatabase::RenameColumn(const string _curr_name, const string _new_name). Os parâmetros devem ser o nome da coluna atual e o novo nome da coluna. O script 16_rename_column.mq5 muda o nome da coluna "EVENTS_NUM" para "EVENTS_NUMBER".


Coluna "EVENTS_NUMBER" renomeada na tabela COUNTRIES

Fig.6 Coluna renomeada “EVENTS_NUMBER” na tabela COUNTRIES


A tabela ficará assim (Fig. 6).


2.16 Combinando linhas de algumas colunas

Suponhamos que desejamos combinar os resultados das amostras em uma tabela. O método CDatabase::Union() é adequado para isso. Vamos atribuir essa tarefa ao script 17_union_some_columns.mq5.

Digamos que temos as duas tabelas "EUROPEAN_COUNTRIES" e "NORTH_AMERICAN_COUNTRIES". A primeira incluirá países europeus e a segunda, países da América do Norte. Vamos primeiro criar tabelas para unir suas linhas. Cada uma das tabelas será uma amostra resultante da primeira tabela "COUNTRIES". No código fica assim:

//--- 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();


Ao executar o script, obteremos as seguintes entradas no log:

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      


A amostra resultante inclui países da Europa e da América do Norte.


2.17 Diferença entre amostras

Digamos que temos 2 amostras. E precisamos encontrar esses registros na primeira amostra que não estão na segunda. O método CDatabase::Except() ajuda aqui.

Tomemos como exemplo as tabelas "COUNTRIES" e "EUROPEAN_COUNTRIES". E vamos ver quais países permanecem se o operador EXCEPT for aplicado à primeira tabela.

A solução para isso está no script 18_except_some_columns.mq5.

Após a execução do programa, as seguintes linhas serão exibidas no log:

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      


É fácil perceber que o resultado foi uma amostra de países que não incluía os europeus. Também não há asiáticos. Eles foram removidos antes.


2.18 Interseção de amostras

Agora vamos tentar descobrir o que as amostras têm em comum. Ou seja, a ideia é encontrar linhas comuns de amostras.

Primeiro, vamos atualizar a tabela "COUNTRIES" e retorná-la ao seu formato original, que incluía os países asiáticos.

Vamos criar duas tabelas temporárias com as colunas "id", "name" e "currency". A primeira incluirá países cujo valor na coluna “COUNTRY_ID” não exceda 578 e a segunda incluirá países cujo valor na mesma coluna seja de pelo menos 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();
     }

Vamos usar os recursos do método CDatabase::Intersect() no script 19_intersect_some_columns.mq5. Como resultado, obtemos as seguintes linhas no log:

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      


O script funcionou corretamente, obtivemos uma lista de países com um valor de id mínimo de 392 e um valor de id máximo de 578.


2.19 Criando representações

Uma representação (view) é um tipo de tabela virtual. Isso é conveniente porque é possível exibir dados selecionados a partir de qualquer outra tabela.

Criaremos representações usando os métodos bool CDatabase::CreateView() e bool CDatabase::CreateViewWhere(). O primeiro cria algum tipo de representação incondicional e o segundo - de acordo com a condição especificada.

Vamos considerar esse exemplo. Temos uma tabela "COUNTRIES". Digamos que seja necessário selecionar todos os países na nova tabela virtual de acordo com as colunas “NAME”, “CONTINENT”, “CURRENCY”.

Vamos resolver esta tarefa usando o script 20_create_view.mq5. Na saída, obtemos a representação “All_countries” (Fig. 7).


Representação “All_countries”

Fig.7 Representação "All_countries" 


Vamos complicar o exemplo e agora selecionar apenas países europeus. O script 21_create_view_where.mq5 fará isso. Como resultado, temos uma tabela virtual contendo apenas países europeus (Fig. 8).


Representação “European”

Fig.8 Representação “European”


Por um lado, as exibições não são tabelas completas, não é possível adicionar, excluir ou atualizar linhas nelas, mas, por outro lado, é possível usá-las para agregar convenientemente os resultados de consultas complexas, selecionar colunas individuais alterando seus nomes, sem afetar os relacionamentos entre as próprias tabelas.


2.20 Removendo representações

É possível remover uma visualização criada anteriormente usando o método CDatabase::DropView().

O método é semelhante ao seu equivalente, que exclui as tabelas DropTable(). Nos exemplos anteriores, era o método delete da exibição que era chamado antes da criação da exibição.

Vamos dizer algumas palavras sobre a construção IF EXISTS. Se houver tentativa de excluir uma representação inexistente com essa construção, o método retornará true; caso contrário, retornará false.

Vamos ver como o script 22_drop_view.mq5funciona.

//--- 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();
     }

Ele primeiro tenta remover a representação inexistente "European_countries1" sem chamar "IF EXISTS". Como resultado, obtemos o erro 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!


Em seguida, o script tenta excluir a exibição "European_countries2", que também não existe, mas com "IF EXISTS". A exclusão da segunda representação será bem-sucedida, mesmo que de fato não tenha havido exclusão.


2.21 Renomeando a tabela

Digamos que devamos renomear a própria tabela. Para fazer isso, vamos usar o método CDatabase::RenameTable(). O script 23_rename_table.mq5 executará o comando de renomeação.


Tabela renomeada COUNTRIES1

Fig.9 Tabela renomeada COUNTRIES1


Como resultado, a tabela atual será chamada de “COUNTRIES1” (Fig.9).


3. Banco de dados de eventos macroeconômicos

Nesta seção, proponho abordar a criação de um banco de dados relacional de eventos macroeconômicos que são cobertos pelo Calendário.

Assim, em primeiro lugar, vamos criar um esquema das tabelas que comporão o futuro banco de dados. É importante observar que no artigo "Receitas MQL5 - Calendário econômico" já vimos as ligações entre as estruturas do calendário. Portanto, em nosso caso, é bastante fácil para o banco de dados criar tabelas e construir ligações para elas.


3.1 Tabelas e ligações

Haverá 3 tabelas brutas no banco de dados:

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

As ligações entre as tabelas são mostradas na Figura 10.


Esquema de ligações entre tabelas no banco de dados Calendar_DB

Fig.10 Esquema de ligações entre tabelas no banco de dados Calendar_DB


A tabela COUNTRIES se torna pai da tabela EVENTS. A última, por sua vez, se torna filha da primeira.

A chave primária da tabela COUNTRIES é a coluna (campo) "COUNTRY_ID". Ela é precedida por um sinal de "+" no diagrama. Para a tabela EVENTS, essa chave é a coluna "EVENT_ID", enquanto a coluna "COUNTRY_ID" é uma chave externa. Ela é precedida por "#" no esquema.

A tabela EVENTS será pai da tabela EVENT_VALUES, e a segunda será filha da primeira.

Na tabela EVENT_VALUES, a chave primária é a coluna (campo) "VALUE_ID" e a chave estrangeira é "EVENT_ID".

As chaves são necessárias para implementar as ligações acima entre as tabelas. As ligações contribuem para a integridade dos dados no banco de dados.

As ligações entre as três tabelas têm uma forma de "um para vários" (1..*). Provavelmente não é muito difícil decifrá-los. A primeira ligação entre países e eventos pode ser representada da seguinte forma: um país tem muitos eventos macroeconômicos e um evento tem apenas um país. A segunda ligação entre eventos e valores de eventos pode ser ilustrada da seguinte forma: um evento tem muitos valores e qualquer valor tem apenas um evento.

Vamos ao código. O script sCreateAndFillCalendarDB.mq5 implementa essas etapas:

  1. criação de um banco de dados de calendário;
  2. criação de tabelas de banco de dados;
  3. preenchimento de tabelas.

Vejamos, por exemplo, como é criada a tabela EVENTS. A consulta final para criar esta tabela fica assim:

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
)


As linhas em que a chave estrangeira é criada são de especial interesse. A linha FOREIGN KEY (COUNTRY_ID) indica que a tabela tem uma chave estrangeira pelo campo COUNTRY_ID. A construção REFERENCES COUNTRIES(COUNTRY_ID) é usada para fazer referência à tabela pai COUNTRIES.

As expressões ON UPDATE CASCADE e ON DELETE CASCADE indicam que, se ao excluir ou alterar uma linha relacionada da tabela pai na tabela filha, as linhas também serão excluídas ou alteradas.

Quanto ao preenchimento de tabelas, abaixo está um bloco de código em que a tabela "COUNTRIES" é preenchida.

//--- 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());
        }
     }


Primeiro, é necessário selecionar a tabela usando o método CDatabase::SelectTable() para manipulação posterior. Aqui podemos fazer uma analogia com a forma como uma posição de negociação é selecionada usando a função nativa ::PositionSelect() para seu processamento posterior.

Em seguida, o método CDatabase::EmptyTable() limpa previamente a tabela.

Em seguida, em um loop, percorremos os países e preenchemos a tabela por colunas

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

A inserção da linha final na tabela é realizada pelo método CDatabase::InsertSingleRow(). Note que aqui, ao preencher a tabela, está envolvido um mecanismo transacional. Saiba mais na seção “Aceleração de transações por embrulhamento em DatabaseTransactionBegin()/DatabaseTransactionCommit()”.

Após o preenchimento de três tabelas, foram obtidos os seguintes resultados: a tabela COUNTRIES contém 23 registros, a tabela EVENTS contém 1500 registros e a tabela EVENT_VALUES contém 158.696 registros (Fig. 11).


Tabela EVENT_VALUES preenchida

Fig.11 Tabela preenchidaEVENT_VALUES


Agora que temos os dados, podemos começar a obter informações, a criar consultas.


3.2 Consultas ao banco de dados

Em geral, todas as consultas ao banco de dados podem ser divididas em 2 grupos:

1) consultas que recebem informações do banco de dados;

2) consultas que alteram dados no banco de dados.

Primeiro, veremos como obter informações de um banco de dados de calendário.


3.2.1 Amostragem do número de eventos por país

Vamos começar consultando o banco de dados para saber quantos eventos macroeconômicos existem por país. Criamos a seguinte consulta acessando a tabela "EVENTS":

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


No código MQL5, tal consulta é feita da seguinte forma:

//--- 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();


E no log do terminal, a saída será uma amostra das colunas originais "COUNTRY_ID" e "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 


A amostra não parece muito legível, pois a coluna "id" é um identificador de país, não um nome de país. Mas os nomes dos países estão em outra tabela - "COUNTRIES".

Para obter o nome do país e o número de eventos do país, devemos criar uma consulta composta (uma consulta dentro de uma consulta).

A primeira versão dessa consulta composta tem a seguinte aparência:

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 versão usa a consulta que criamos no início. Mas agora ela se tornou parte de outra consulta, mudando assim para uma subconsulta. 

E a segunda variante de consulta pode ser implementada no formulário CTE:

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


No MQL5, a consulta composta é feita da seguinte forma:

//--- 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();


E a expressão de tabela (CTE) é implementada da seguinte forma:

//--- 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 as versões imprimirão os seguintes resultados da consulta no log:

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 


É fácil ver que, acima de tudo, o calendário presta atenção aos eventos americanos (existem 247).

Complicamos um pouco tudo, e adicionamos uma coluna à amostra para calcular quantos eventos importantes ocorrem em um determinado país. O grau de importância é definido na coluna “IMPORTANCE”. Selecionamos apenas os eventos que têm o valor “High”.

Primeiro, trabalhamos com a tabela "EVENTS". Aqui precisamos criar duas amostras. A primeira amostra é uma contagem do número de eventos por país. Isso já foi concluído acima. A segunda amostra é uma contagem do número de eventos importantes por país. E, por fim, as duas amostras precisarão ser mescladas.

O código SQL da consulta é apresentado assim:

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


Quanto à implementação em MQL5, o código fica assim:

//--- 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, obtemos as seguintes entradas de log:

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 


Na seleção final, resta apenas substituir a coluna “id” por “país”.

Vamos criar uma consulta composta novamente, e aproveitamos o fato de já ter sido escrita anteriormente. No final da amostra, organizamos os valores na coluna "imp_events_number" em ordem decrescente. A consulta composta é assim:

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


No código MQL5, a solicitação é implementada da seguinte forma:

//--- 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();


E agora obtemos a amostra desejada no log:

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 pode ser visto na amostra, os Estados Unidos têm os eventos mais importantes, com 20. Em segundo lugar está o Reino Unido, com 13. O terceiro lugar é ocupado pela União Europeia, com 11. O Japão está apenas em 6º lugar, com 7.

E vamos usar uma consulta para encontrar os países que não têm nenhum evento importante. Para fazer isso, encontramos a diferença entre as duas amostras. A primeira amostra inclui todos os países que retiramos da tabela "COUNTRIES" e a segunda abrange a coluna com os países da consulta composta anterior.

O código SQL ficará assim:

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
       )


O código MQL5 será mais simples, pois aproveitaremos o fato de que a consulta anterior se tornará nossa nova 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();


Após a execução do código, recebemos as seguintes entradas no log:

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 


Ou seja, de todos os países, apenas a Itália e a Espanha não têm eventos importantes. As consultas sobre eventos de países em MQL5 foram executadas no script sRequest1.mq5.


3.2.2 Amostra de valores do PIB por país

Neste exemplo, faremos uma consulta ao banco de dados, a partir daí obtemos uma amostra de valores do PIB para vários países. Como valor do PIB, tomamos o indicador “Produto Interno Bruto (PIB) q/q” (para o 3º trimestre).

Como haverá várias amostras, a consulta será composta.

Primeiro, vamos olhar para as economias de países que têm um indicador de PIB trimestral.

O código SQL é apresentado assim:

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


A implementação em MQL5 tem esse aspeto (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();


E uma impressão do log após a execução da 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 o indicador necessário existe em 21 países. O indicador não é usado na Índia, nem como um indicador mundial ("Worldwide").

Agora precisamos obter uma amostra dos valores do indicador do terceiro trimestre e vinculá-la à primeira amostra por ID de evento.

A consulta SQL fica assim:

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' )


Quanto ao código MQL5, a consulta composta é implementada da seguinte forma:

//--- 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();


E após a execução, as seguintes linhas aparecerão no log:

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 


É fácil perceber que existem vários valores na seleção para alguns eventos com o mesmo event_id. Por exemplo, as entradas 2-4 se referem ao número na UE. Como o PIB foi estimado em várias leituras, há vários valores para o indicador. Como resultado, há 36 registros na amostra resultante, o que é claramente mais do que o número de países para os quais este indicador é calculado.

Se for necessário obter uma amostra apenas dos valores mais recentes de um determinado evento, a consulta deverá incluir uma opção de agrupamento e um filtro para os resultados do grupo. Em seguida, obtemos a seguinte consulta SQL composta:

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)


Iremos agrupar os registros pela coluna (campo) "event_id". E como registro principal, se houver vários, pegaremos aquele com o valor máximo na coluna (campo) "value_id". Assim, por exemplo, apenas um dos três registros para a União Europeia será selecionado:

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, as seguintes entradas aparecerão no log:

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 


Agora há 21 registros na amostra. E o toque final é substituir o código do país pelo seu nome. Vamos alterar a consulta SLQ anterior para a seguinte:

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


Ao longo do caminho, implementamos esta consulta composta em 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();


A amostra desejada será impressa no log:

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 


Gostaria de ressaltar que apesar de o problema ter sido resolvido por meio de várias abordagens, a possibilidade de incluir uma consulta na outra facilitou bastante.


Considerações finais

Espero que o artigo desperte o interesse daqueles traders e desenvolvedores que usam dados macroeconômicos para criar suas estratégias. Eu também ousaria sugerir que provavelmente não existem tais indicadores macro para poder construir uma boa estratégia. Mas, por exemplo, esses indicadores podem ser úteis como um complemento aos dados brutos das redes neurais. 

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/11977

Arquivos anexados |
CalendarDB.zip (52.66 KB)
Desenvolvendo um sistema de Replay - Simulação de mercado (Parte 11): Nascimento do SIMULADOR (I) Desenvolvendo um sistema de Replay - Simulação de mercado (Parte 11): Nascimento do SIMULADOR (I)
Para poder usar dados que formam barras, precisamos abandonar o replay e começar a desenvolver um simulador. Não sabemos como ela foi criada. Estaremos utilizando as barras de 1 minuto, justamente pelo motivo, de elas nos darem, um nível de complexidade mínimo.
Desenvolvendo um sistema de Replay - Simulação de mercado (Parte 10): Usando apenas dados reais na replay Desenvolvendo um sistema de Replay - Simulação de mercado (Parte 10): Usando apenas dados reais na replay
Aqui vamos ver como você pode utilizar dados mais fieis ( tickets negociados ) no sistema de replay, sem necessariamente ter que se preocupar se eles estão ou não ajustados.
Desenvolvendo um sistema de Replay - Simulação de mercado (Parte 12): Nascimento do SIMULADOR (II) Desenvolvendo um sistema de Replay - Simulação de mercado (Parte 12): Nascimento do SIMULADOR (II)
Desenvolver um simulador pode ser muito mais interessante do que parece. Então vamos dar mais alguns passos nesta direção, pois a coisa está começando a ficar empolgante.
Desenvolvimento de uma DLL experimental com suporte a multithreading em C++ para MetaTrader 5 no Linux Desenvolvimento de uma DLL experimental com suporte a multithreading em C++ para MetaTrader 5 no Linux
Este artigo descreve o processo de desenvolvimento para a plataforma MetaTrader 5 exclusivamente em Linux. O produto final funciona tanto no Windows quanto no Linux sem nenhum problema. Veremos o Wine e o Mingw, ferramentas importantes para o desenvolvimento entre plataformas. O Mingw apresenta threads (POSIX e Win32), que você deve levar em conta ao escolher uma ferramenta adequada. Criaremos também uma DLL para testar o conceito e usá-la no código MQL5, comparando o desempenho das duas implementações de threading. O artigo tem como objetivo ser um ponto de partida para a realização de seus próprios experimentos. Depois de ler este artigo, você será capaz de criar ferramentas para o MetaTrader no Linux.