English Русский 中文 Español 日本語 Português
preview
MQL5 Kochbuch — Datenbank für makroökonomische Ereignisse

MQL5 Kochbuch — Datenbank für makroökonomische Ereignisse

MetaTrader 5Beispiele | 30 März 2023, 10:35
304 0
Denis Kirichenko
Denis Kirichenko

Einführung

Dieser Artikel befasst sich mit der Gruppierung und Verwaltung von Daten, die makroökonomische Kalenderereignisse beschreiben.

In der modernen Welt ist der Informationsfluss allgegenwärtig. Bei der Analyse von Ereignissen hat man es also mit großen Datenmengen zu tun. Auch wenn der Artikel in größerem Umfang Fragen behandelt, die nicht den Inhalt, sondern die Form betreffen, so scheint es doch, dass die richtige Organisation und Strukturierung von Daten viel dazu beiträgt, dass diese Daten zu Informationen werden.

Wir werden diese Aufgaben mit Hilfe von SQLite lösen. Der Entwickler hat Unterstützung für den Umgang mit SQLite direkt aus MQL5 build 2265 (6. Dezember 2019) hinzugefügt. Zuvor musste man verschiedene Konnektoren verwenden, wie beschrieben z. B. in dem Artikel SQL und MQL5: Mit der SQLite Datenbank arbeiten.


1. Dokumentation und zusätzliche Materialien

Schauen wir uns die Dokumentation an, insbesondere die Abschnitte über die Handhabung von Datenbanken. Der Entwickler hat 26 Funktionen integriert:

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

Es gibt auch Blöcke mit statistischen und mathematischen Funktionen, die kürzlich hinzugefügt wurden. Der Artikel SQLite: Natives Arbeiten mit SQL-Datenbanken in MQL5 kann als Ausgangspunkt für die Untersuchung dieser Funktionen dienen.


2. Die Klasse CDatabase

Erstellen wir die Klasse CDatabase, um die Handhabung von Datenbanken zu erleichtern. Zunächst beschreiben wir die Zusammensetzung der Klasse. Dann überprüfen wir die Funktionsweise anhand von Beispielen.

Zu den Datenelementen der Klasse CDatabase gehören die folgenden:

  • m_name - Name der Datenbankdatei (mit der Erweiterung);
  • m_handle - Datenbank-Handle;
  • m_flags - Kombination von Flags;
  • m_table_names - Tabellennamen;
  • m_curr_table_name - Name der aktuellen Tabelle;
  • m_sql_request_ha - Handle der letzten SQL-Anfrage;
  • m_sql_request - letzte SQL-Anfrage.

Was die Methoden angeht, so würde ich sie in mehrere Gruppen unterteilen:

  1. Methoden, die native Funktionen für den Umgang mit Datenbanken enthalten (API MQL5-Funktionen);
  2. Methoden zur Handhabung von Tabellen (tables);
  3. Methoden zur Bearbeitung von Anfragen (requests);
  4. Methoden für die Arbeit mit Ansichten (views);
  5. Methoden zum Abrufen von Datenelementwerten (get-Methoden).

SQLite bietet mehrere Anfrageformulare, die sowohl einfach als auch komplex sein können. Mein Ziel ist es nicht, für jedes dieser Formulare eine eigene Methode in der Klasse CDatabase zu erstellen.  Wenn die Klasse keine Methode für eine bestimmte Anfrage hat, kann die Anfrage mit der universellen Methode CDatabase::Select() gebildet werden.

 

Schauen wir uns nun die Beispiele für die Verwendung der CDatabase-Klassenmerkmale an.


2.1 Erstellen einer Datenbank

Erstellen wir unsere erste Kalenderdatenbank mit dem Skript 1_create_calendar_db.mq5.  Das Skript soll nur wenige Codezeilen enthalten.

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

Nach der Ausführung des Skripts sehen wir, dass die Datenbankdatei test_calendar_db.sqlite in %MQL5\Files\Databases erschienen ist (Abb. 1).


test_calendar_db.sqlite Datenbankdatei

Abb. 1. test_calendar_db.sqlite Datenbankdatei


Wenn wir diese Datei im Code-Editor öffnen, werden wir sehen, dass die Datenbank leer ist (Abb. 2).


test_calendar_db Datenbank

Abb. 2. test_calendar_db Datenbank


2.2 Erstellen einer Tabelle

Lassen Sie uns versuchen, die Datenbank zu füllen. Zu diesem Zweck erstellen wir die Tabelle COUNTRIES, in die wir eine Liste der Länder eintragen, deren Kalenderereignisse anschließend von unseren Abfragen verarbeitet werden sollen. Das Skript 2_create_countries_table.mq5 wird diese Aufgabe übernehmen.

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

Nach der Ausführung des Skripts können wir feststellen, dass die Tabelle COUNTRIES in der Datenbank erschienen ist (Abb. 3).


Die leere Tabelle COUNTRIES

Abb. 3. Die leere Tabelle COUNTRIES


2.30 Füllen der Tabelle

Füllen wir die neue Tabelle mit Daten. Dazu verwenden sie die Funktionen der Klasse CiCalendarInfo. Weitere Details über die Klasse finden Sie im Artikel MQL5 Kochbuch – Wirtschaftskalender. Die Aufgabe wird von dem Skript 3_fill_in_countries_table.mq5 übernommen.

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

Drucken wir die Daten der Tabelle COUNTRIES im Protokoll aus.

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      


In MetaEditor sieht die Tabelle wie folgt aus (Abb. 4).

Gefüllte Tabelle COUNTRIES

Abb. 4. Gefüllte Tabelle COUNTRIES



2.4 Auswählen einiger Tabellenspalten

Lassen Sie uns nun die Daten der Tabelle COUNTRIES bearbeiten. Angenommen, wir wollen die folgenden Spalten auswählen:

  • „COUNTRY_ID“;
  • „COUNTRY_NAME“;
  • „COUNTRY_CODE“;
  • „COUNTRY_CONTINENT“;
  • „CURRENCY“.

Wir erstellen eine SQL-Abfrage mit dem Skript 4_select_some_columns.mq5 auf folgende Weise:

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


Beim Ausdrucken der Abfrage erhalten wir:

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      

Offensichtlich wurde ohne Sortierung ausgewählt.


2.5 Auswählen einiger Spalten der sortierten Tabelle

Sortieren wir die Daten in der Tabelle nach der Spalte „COUNTRY_ID“. Diese Anfrage hat die folgende Implementierung im Skript5_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();
   }
//+------------------------------------------------------------------+


Das Ergebnis der Abfrageausführung erscheint im Protokoll:

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      

Das Skript funktioniert korrekt - die Spalte „COUNTRY_ID“ beginnt bei 0 und endet bei 999.


2.6 Auswahl von gruppierten Ergebnissen einer bestimmten Tabellenspalte

Verwenden wir nun das Skript 6_select_some_grouped_columns.mq5, um nach Kontinenten gruppierte Ländernamen zu erhalten. Die Aufgabe besteht darin, die Anzahl der Länder zu ermitteln, die in jeder Zeile des Kontinents enthalten sind. Die Länder werden in der Spalte „NAME“ ausgewählt. Nach der Ausführung des Skripts erscheinen die folgenden Zeilen im Protokoll:

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 


„Europe“ umfasst die meisten Länder - 9, während „Africa“ und „South America“ jeweils nur 1 Land umfassen. Außerdem gibt es noch „World“.


2.7 Auswählen eindeutiger Werte einer bestimmten Tabellenspalte

Verwenden wir nun das Skript 7_select_distinct_columns.mq5, um eindeutige Werte in der Spalte CURRENCY zu versammeln. Es gibt Länder, die die gleiche Währung verwenden. Um Wiederholungen zu vermeiden, führen wir das Skript aus. Wir können das folgende Ergebnis sehen:

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      

Der Kalender enthält also Ereignisse für insgesamt 18 Währungen und eine Gruppe von Ereignissen, die für alle Währungen gelten.

Es ist leicht zu erkennen, dass die Methoden zur Auswahl gruppierter Ergebnisse und zur Auswahl eindeutiger Werte Ähnlichkeiten aufweisen. Lassen Sie uns dies anhand eines Beispiels demonstrieren.

Das Skript 8_compare_ grouped_and_distinct_columns.mq5 zeigt die folgenden Ergebnisse im Protokoll an:

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             


Die Methoden haben die gleichen inhaltlichen Ergebnisse geliefert, weil wir die Spalte „CONTINENT“ als Gruppierungsspalte (Feld) für die erste Methode definiert haben. Interessanterweise hat die erste Methode auch die Auswahl für uns sortiert.


2.8 Auswahl von geordneten eindeutigen Werten einer bestimmten Tabellenspalte

Die Werte der Spalte CURRENCY wurden vom Skript 7_select_distinct_columns.mq5 unsortiert angezeigt. Machen wir eine sortierte Auswahl (Skript 9_select_sorted_distinct_columns.mq5). Die Spalte „COUNTRY_ID“ sei das Sortierkriterium. Als Ergebnis der Log-Manipulationen erhalten wir:

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      


Jetzt sind alle Währungen sortiert. Standardmäßig wird die Sortierung in aufsteigender Reihenfolge vorgenommen.


2.9 Auswählen einiger Tabellenspalten nach Bedingungen

Zuvor haben wir bereits eine SQL-Abfrage zur Auswahl von Tabellenspalten erstellt. Jetzt können wir die Spalten abrufen, wenn eine Bedingung erfüllt ist. Angenommen, wir wollen Länder auswählen, deren ID gleich oder größer als 392 und gleich oder kleiner als 840 ist. Diese Aufgabe wird gelöst durch das Skript 10_select_some_columns_where.mq5 gelöst.

Nach der Ausführung des Skripts wird im Protokoll Folgendes angezeigt:

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      


Mit anderen Worten: Die Stichprobe beginnt mit dem Ländercode 392 und endet mit 840. 


2.10 Einige der sortierten Tabellenspalten nach Bedingung auswählen

Machen wir das vorherige Problem noch komplizierter. Fügen wir der Stichprobe ein Sortierkriterium hinzu - das ist die Zugehörigkeit des Landes zum Kontinent. Die aktuelle Aufgabe wird mit dem Skript 11_select_some_sorted_columns_where.mq5 gelöst. Nach der Ausführung sehen wir die folgenden Zeilen im Protokoll:

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      


 Folglich steht „South Africa“ in der Stichprobe an erster Stelle, da der Kontinent „Africa“ in der Liste der Kontinente an erster Stelle steht.


2.11 Aktualisieren einiger Tabellenspalten nach Bedingungen

Nehmen wir an, dass wir die Zeilen in den ausgewählten Spalten aktualisieren müssen. Außerdem müssen wir dies nach Erfüllung einer Vorbedingung tun.

Nehmen wir die asiatischen Länder und setzen die Werte für sie in den Spalten CURRENCY und CURRENCY_SYMBOL zurück. Die Aufgabe wird vom Skript 12_update_some_columns.mq5 ausgeführt.

Als Ergebnis der Ausführung erhalten wir die folgende Tabelle:

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 Ersetzen und Hinzufügen einiger Tabellenzeilen

Fahren wir mit der Arbeit an den Tabellen fort. Lassen Sie uns nun versuchen, einige Zeilen in der ausgewählten Tabelle zu ersetzen.

Angenommen, wir müssen das aktuelle Symbol „Mex$“ durch „Peso mexicano“ für „Mexiko“ in der Spalte CURRENCY_SYMBOL ersetzen. Das Skript 13_replace_some_rows.mq5 wird das ausführen.

In der aktuellen Version der LÄNDERTABELLE hat Mexiko den folgenden Eintrag:

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


mexico


Um diese Zeile in der Tabelle zu ersetzen, müssen wir einen eindeutigen Wert für die ausgewählte Zeile festlegen. Andernfalls wird SQLite nicht verstehen, was wir ersetzen wollen.

Nehmen wir an, dass dieser Wert der Name des Landes ist (Spalte NAME). Dann wird die Ersetzungsfunktion im Code wie folgt dargestellt:

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


Bei der Ausführung des Skripts wird folgende Fehlermeldung angezeigt:

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


Offensichtlich ist die Beschränkung NOT NULL verletzt worden. Bei der Erstellung der Tabelle wurde ursprünglich festgelegt, dass die Spalte COUNTRY_ID nicht Null enthalten darf. Es ist also notwendig, einen Wert für diese Spalte hinzuzufügen. Um keine halbleere Zeile zu erhalten, fügen wir Werte für alle Spalten hinzu.

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

Jetzt funktioniert das Skript einwandfrei. Die folgenden Einträge erscheinen im Protokoll:

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   


Wenn es keine Zeile mit Daten über Mexiko gäbe, würde sie einfach hinzugefügt werden. Mit anderen Worten: Das Ersetzen ist auch die Operation zum Hinzufügen von Tabellenzeilen.


2.13 Löschen einiger Zeilen der Tabelle

Nun wollen wir sehen, wie wir die Anzahl der Tabellenzeilen verringern können, anstatt sie zu erhöhen. Dazu erstellen wir das Skript 14_delete_some_rows.mq5, das auf Anfrage die Zeilen mit Bezug zu Asien aus der ausgewählten Tabelle löscht.

Nach der Ausführung des Skripts wird die Abschlusstabelle angezeigt:

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         


Es wurden keine asienbezogenen Zeilen gefunden.


2.14 Hinzufügen von Spalten zur Tabelle

Das Hinzufügen neuer Spalten zu einer Tabelle ist ebenfalls eine recht häufige Aufgabe.

Angenommen, wir müssen unsere Tabelle COUNTRIES erweitern und eine Spalte hinzufügen, die die Anzahl der makroökonomischen Ereignisse enthält, die in den Kalender fallen.

Die Aufgabe wird von dem Skript 15_add_new_column.mq5 ausgeführt.

Überprüfen wir nach der Ausführung des Skripts die Tabelle (Abb. 5). Sie enthält jetzt die neue Spalte EVENTS_NUM.


Neue Spalte EVENTS_NUM in der Tabelle COUNTRIES

Abb. 5. Die neue Spalte EVENTS_NUM in der Tabelle COUNTRIES


2.15 Spalten in der Tabelle umbenennen

Das Umbenennen von Spalten erfolgt mit CDatabase::RenameColumn(const string _curr_name, const string _new_name). Wir geben den aktuellen und den neuen Spaltennamen als Parameter an. Das Skript 16_rename_column.mq5 ersetzt den Spaltennamen EVENTS_NUM durch EVENTS_NUMBER.


Die umbenannte Spalte EVENTS_NUMBER im Land COUNTRIES

Abb. 6. Die umbenannte Spalte EVENTS_NUMBER in der Tabelle COUNTRIES


Die Tabelle sieht nun wie folgt aus (Abb. 6).


2.16 Verkettung von Zeilen

Angenommen, wir müssen die Stichprobenergebnisse in einer einzigen Tabelle verketten. Dies kann mit der Methode CDatabase::Union() erreicht werden. Diese Aufgabe erledigt das Skript 17_union_some_columns.mq5.

Angenommen, wir haben zwei Tabellen - EUROPEAN_COUNTRIES und NORTH_AMERICAN_COUNTRIES. Die erste Tabelle enthält die europäischen Länder, die zweite die nordamerikanischen Länder. Erstellen wir zunächst Tabellen, um dann ihre Zeilen zu verketten. Jede der Tabellen ist die resultierende Auswahl aus der Tabelle COUNTRIES. Im Code sieht das wie folgt aus:

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


Bei der Ausführung des Skripts werden die folgenden Einträge im Protokoll angezeigt:

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      


Die resultierende Stichprobe umfasst europäische und nordamerikanische Länder.


2.17 Unterschied zwischen den Stichproben

Nehmen wir an, wir haben zwei Stichproben. Wir müssen Einträge in der ersten Stichprobe finden, die in der zweiten Stichprobe nicht vorhanden sind. Dies kann mit der Methode CDatabase::Except() erreicht werden.

Nehmen wir als Beispiel die Tabellen COUNTRIES und EUROPEAN_COUNTRIES. Schauen wir uns an, welche Länder übrig bleiben, wenn der EXCEPT-Operator auf die erste Tabelle angewendet wird.

Die Lösung bietet das Skript 18_except_some_columns.mq5.

Die folgenden Zeilen werden im Protokoll als Ergebnis der Skriptausführung angezeigt:

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      


Wie wir sehen können, enthält die Stichprobe keine europäischen Länder. Die Asiaten fehlen ebenfalls, da sie zuvor entfernt wurden.


2.18 Beispiel einer Schnittmenge

Nun wollen wir herausfinden, welche gemeinsamen Merkmale die Muster haben. Mit anderen Worten: Die Aufgabe besteht darin, gemeinsame Zeilen in den Stichproben zu finden.

Zunächst aktualisieren wir die Tabelle COUNTRIES und bringen sie in ihre ursprüngliche Form zurück, in der die asiatischen Länder enthalten waren.

Wir erstellen zwei temporäre Tabellen mit den Spalten „id“, „name“ und „currency“. Die erste enthält Länder, deren Wert in der Spalte COUNTRY_ID nicht höher als 578 ist, und die zweite enthält Länder, deren Wert in derselben Spalte mindestens 392 beträgt.

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

Verwenden wir die Funktionen der Methode CDatabase::Intersect() im Skript 19_intersect_some_columns.mq5. Als Ergebnis erhalten wir die folgenden Zeilen im Protokoll:

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      


Das Skript hat korrekt funktioniert. Wir erhalten eine Liste von Ländern, deren kleinste ID 392 und größte 578 beträgt.


2.19 Erstellen von Ansichten

Ein View (Ansicht) ist eine Art virtueller Tisch. Der Vorteil ist, dass Sie Daten aus jeder anderen Tabelle anzeigen können.

Wir werden Ansichten mit den Methoden bool CDatabase::CreateView() und bool CDatabase::CreateViewWhere() erstellen, wobei die erste eine Art unbedingte Ansicht erstellt, während die zweite eine Ansicht gemäß einer bestimmten Bedingung erstellt.

Betrachten wir folgendes Beispiel. Wir haben die Tabelle COUNTRIES. Nehmen wir an, dass wir für die neue virtuelle Tabelle alle Länder nach den Spalten NAME, CONTINENT und CURRENCY auswählen müssen.

Lösen wir dieses Problem mit dem Skript 20_create_view.mq5. Das Ergebnis ist die Ansicht „All_countries“ (Abb. 7).


Ansicht „Alle_Länder“

Abb. 7. Ansicht „Alle_Länder“ 


Verkomplizieren wir das Beispiel und wählen wir nur europäische Länder aus. Das Skript 21_create_view_where.mq5 wird das erledigen. Als Ergebnis haben wir eine virtuelle Tabelle, die nur europäische Länder enthält (Abb. 8).


Ansicht „Europa“

Abb. 8. Ansicht „Europa“


Ansichten (views) sind keine vollwertigen Tabellen, da wir in ihnen keine Zeilen hinzufügen, löschen oder aktualisieren können. Sie können jedoch verwendet werden, um die Ergebnisse komplexer Abfragen bequem zu aggregieren und einzelne Spalten auszuwählen, wobei die Namen geändert werden können, ohne die Beziehungen zwischen den Tabellen selbst zu beeinträchtigen.


2.20 Entfernen von Ansichten

Mit der Methode CDatabase::DropView() können wir eine zuvor erstellte Ansicht entfernen.

Die Methode ähnelt ihrem Gegenstück DropTable(), das die Tabellen entfernt. In den vorherigen Beispielen wurde die Methode zum Löschen der Ansicht aufgerufen, bevor die Ansicht erstellt wurde.

Nun ist es an der Zeit, ein paar Worte über die IF EXISTS-Konstruktion zu verlieren. Wenn wir versuchen, eine nicht existierende Ansicht mit dieser Konstruktion zu löschen, gibt die Methode „true“ zurück, andernfalls „false“.

Schauen wir uns an, wie das Skript 22_drop_view.mq5 funktioniert.

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

Zunächst wird versucht, die nicht existierende Ansicht „European_countries1“ zu entfernen, ohne IF EXISTS aufzurufen. Als Ergebnis erhalten wir den Fehler 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!


Danach versucht das Skript, die ebenfalls nicht existierende Ansicht „European_countries2“ mit IF EXISTS zu löschen. Das Löschen der zweiten Ansicht wird erfolgreich sein, auch wenn keine Löschung stattfindet.


2.21 Umbenennen einer Tabelle

Nehmen wir an, wir stehen vor der Aufgabe, die Tabelle selbst umzubenennen. Wenden wir uns dazu der Methode CDatabase::RenameTable() zu. Die Umbenennung erfolgt durch das Skript 23_rename_table.mq5 Skript.


Umbenannte Tabelle COUNTRIES1

Abb. 9. Umbenannte Tabelle COUNTRIES1


Infolgedessen erhält die aktuelle Tabelle den Namen COUNTRIES1 (Abb. 9).


3. Datenbank für makroökonomische Ereignisse

In diesem Abschnitt schlage ich vor, mit dem Aufbau einer relationalen Datenbank der im Kalender erfassten makroökonomischen Ereignisse zu beginnen.

Erstellen wir also zunächst eine Tabellenstruktur, aus der die künftige Datenbank bestehen wird. Im Artikel „MQL5 Kochbuch - Wirtschaftskalender“ wurden bereits Kalenderstrukturen besprochen. Daher ist es in unserem Fall recht einfach, Datenbanktabellen zu erstellen und Beziehungen für sie festzulegen.


3.1 Tabellen und relationale Verbindungen

Die Datenbank soll drei Quelltabellen enthalten:

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

Die relationalen Verbindungen zwischen den Tabellen sind in Abb. 10 dargestellt.


Beziehungsstruktur zwischen den Tabellen in der Datenbank Calendar_DB

Abb. 10. Die Struktur der Verbindungen zwischen den Tabellen in der Datenbank Calendar_DB


Die Tabelle COUNTRIES wird zur übergeordneten Tabelle für die Tabelle EVENTS. Letztere wiederum wird von der Ersteren abgeleitet.

Der Primärschlüssel für die Tabelle COUNTRIES ist die Spalte COUNTRY_ID (Feld). In der Abbildung ist ihm das „+“-Zeichen vorangestellt. Für die Tabelle EVENTS ist der Schlüssel die Spalte EVENT_ID, während die Spalte COUNTRY_ID ein externer Fremdschlüssel ist. In der Struktur ist ihm das Symbol „#“ vorangestellt.

Die Tabelle EVENTS wird zur übergeordneten Tabelle der Tabelle EVENT_VALUES, während die zweite Tabelle zur untergeordneten Tabelle der ersten Tabelle wird.

In der Tabelle EVENT_VALUES ist der Primärschlüssel die Spalte (Feld) VALUE_ID, der externe Schlüssel ist EVENT_ID.

Die Schlüssel werden benötigt, um die Beziehungen zwischen den oben genannten Tabellen herzustellen. Die Beziehungen tragen ihrerseits zur Integrität der Daten in der Datenbank bei.

Die Beziehungen zwischen den drei Tabellen sind in der Form „one-to-many“ (eins-zu-vielen, 1..*). Ich glaube, es wird nicht schwer sein, sie zu entschlüsseln. Die erste Verbindung zwischen Ländern und Ereignissen kann wie folgt dargestellt werden: Ein Land hat viele makroökonomische Ereignisse, während ein Ereignis nur ein Land hat. Der zweite Zusammenhang zwischen Ereignissen und Ereigniswerten lässt sich wie folgt veranschaulichen: Ein Ereignis hat viele Werte, während jeder Wert nur ein Ereignis hat.

Kommen wir nun zum Code. Das Skript sCreateAndFillCalendarDB.mq5 umfasst folgende Schritte:

  1. Erstellen einer Kalenderdatenbank;
  2. Erstellen der Datenbanktabellen;
  3. Füllen der Tabellen.

Schauen wir uns zum Beispiel an, wie die Tabelle EVENTS erstellt wird. Die endgültige Abfrage zur Erstellung dieser Tabelle sieht wie folgt aus:

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
)


Von besonderem Interesse sind die Zeichenfolgen, in denen der externe Schlüssel erstellt wird. Die Zeile FOREIGN KEY (COUNTRY_ID) bedeutet, dass die Tabelle über einen externen Schlüssel mit dem Feld COUNTRY_ID verfügt. Die Konstruktion REFERENCES COUNTRIES(COUNTRY_ID) wird verwendet, um auf die übergeordnete Tabelle COUNTRIES zu verweisen.

Die Ausdrücke ON UPDATE CASCADE und ON DELETE CASCADE bedeuten, dass, wenn eine Bezugszeile aus der übergeordneten Tabelle gelöscht oder geändert wird, die Zeilen in der untergeordneten Tabelle ebenfalls gelöscht oder geändert werden.

Was das Füllen von Tabellen betrifft, so ist unten ein Codeblock zu sehen, in dem die Tabelle COUNTRIES gefüllt wird.

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


Um mit der Tabelle weiterarbeiten zu können, müssen wir sie zunächst mit der Methode CDatabase::SelectTable() auswählen. Hier können wir eine Analogie dazu ziehen, wie eine Handelsposition mit Hilfe der nativen Funktion ::PositionSelect() für ihre weitere Verarbeitung ausgewählt wird.

Anschließend wird die Tabelle mit der Methode CDatabase::EmptyTable() vorläufig geleert.

Gehen Sie dann in einer Schleife durch die Länder und füllen Sie die Tabelle nach Spalten

  • „COUNTRY_ID“,
  • „COUNTRY_NAME“,
  • „COUNTRY_CODE“,
  • „CONTINENT“,
  • „CURRENCY“,
  • „CURRENCY_SYMBOL“,
  • „URL_NAME“.

Die letzte Zeile wird mit der Methode CDatabase::InsertSingleRow() in die Tabelle eingefügt. Das Füllen der Tabelle erfolgt über einen transaktionalen Mechanismus. Weitere Informationen finden Sie im Abschnitt „Beschleunigung von Transaktionen durch Einhüllen in DatabaseTransactionBegin()/DatabaseTransactionCommit()“.

Das Füllen der drei Tabellen führte zu folgenden Ergebnissen: Die Tabelle COUNTRIES enthält 23 Einträge, die Tabelle EVENTS enthält 1500 Einträge und die Tabelle EVENT_VALUES 158 696 Einträge (Abb. 11).


Gefüllte Tabelle EVENT_VALUES

Abb. 11. Gefüllte Tabelle EVENT_VALUES


Da wir nun die Daten haben, können wir mit der Erstellung der Abfragen beginnen.


3.2 Datenbankabfragen

Im Großen und Ganzen lassen sich alle Datenbankabfragen in zwei Gruppen einteilen:

1) Anfragen, die Daten aus der Datenbank abrufen;

2) Anfragen, die Daten in der Datenbank verändern.

Lassen Sie uns zunächst die Beispiele für den Abruf von Informationen aus der Kalenderdatenbank behandeln.


3.2.1 Stichprobenartige Anzahl von Ereignissen nach Ländern

Fragen wir zunächst die Datenbank, wie viele makroökonomische Ereignisse es in jedem Land gibt. Wir erstellen die folgende Abfrage unter Bezugnahme auf die Tabelle „EVENTS“:

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


Im MQL5-Code ist eine solche Anfrage wie folgt implementiert:

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


Das Ergebnis ist die folgende Auswahl nach den Quellspalten COUNTRY_ID und COUNT(EVENT_ID), die im Terminalprotokoll angezeigt wird:

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 


Die Auswahl sieht nicht sehr lesbar aus, weil die Spalte „id“ eine Länder-ID und kein Ländername ist. Die Ländernamen sind in der Tabelle LÄNDER zu finden.

Um den Namen des Landes und die Anzahl der Länderereignisse zu erhalten, müssen wir eine zusammengesetzte Abfrage erstellen (eine Abfrage innerhalb einer Abfrage).

Die erste Version einer solchen Verbundabfrage sieht wie folgt aus:

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


Diese Option verwendet die Abfrage, die wir zu Beginn erstellt haben. Aber jetzt ist sie Teil einer anderen Abfrage geworden, wodurch sich ihre Form in die Form einer Unterabfrage geändert hat. 

Die zweite Version der Anfrage kann in Form von CTE umgesetzt werden.

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


Im MQL5-Code ist eine zusammengesetzte Abfrage wie folgt implementiert:

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


Der Tabellenbefehl (CTE) ist wie folgt implementiert:

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


Beide Optionen geben die folgenden Abfrageergebnisse im Protokoll aus:

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 


Es ist leicht zu erkennen, dass der Kalender den Ereignissen in den USA die größte Aufmerksamkeit schenkt - es sind 247 an der Zahl.

Erschweren wir die Aufgabe ein wenig und fügen wir der Stichprobe eine Spalte hinzu, in der wir berechnen, wie viele wichtige Ereignisse in einem bestimmten Land stattfinden. Die Wichtigkeit wird in der Spalte IMPORTANCE definiert. Es werden nur die Ereignisse ausgewählt, die den Wert Hoch haben.

Lassen Sie uns zunächst mit der Tabelle EVENTS arbeiten. Hier müssen wir zwei Muster erstellen. Die erste Stichprobe ist eine Zählung der Anzahl der Ereignisse nach Ländern. Diese Aufgabe wurde bereits oben erledigt. Die zweite Stichprobe ist eine Zählung der Anzahl der wichtigen Ereignisse nach Ländern. Schließlich müssen wir beide Stichproben kombinieren.

Der SQL-Code der Abfrage sieht wie folgt aus:

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


Was die MQL5-Implementierung betrifft, so sieht der Code wie folgt aus:

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

Als Ergebnis erhalten wir die folgenden Protokolleinträge:

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 


In der endgültigen Auswahl muss nur noch die Spalte „id“ durch „country“ ersetzt werden.

Lassen Sie uns wieder eine zusammengesetzte Abfrage erstellen. Wir werden uns die Tatsache zunutze machen, dass seine Teile früher geschrieben wurden. Am Ende sortieren wir die Stichprobe in absteigender Reihenfolge nach den Werten in der Spalte „imp_events_number“. Die zusammengesetzte Abfrage sieht wie folgt aus:

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


Im MQL5-Code ist die Anfrage wie folgt implementiert:

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


Jetzt erhalten wir das gewünschte Muster im Protokoll:

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 


Wie aus der Stichprobe hervorgeht, haben die Vereinigten Staaten die meisten wichtigen Ereignisse - 20. An zweiter Stelle steht das Vereinigte Königreich - 13. Den dritten Platz belegt die EU mit 11. Japan belegt 6. Platz - 7.

Verwenden wir eine Abfrage, um die Länder zu finden, in denen keine wichtigen Ereignisse stattfinden. Zu diesem Zweck müssen wir die Differenz zwischen den beiden Stichproben ermitteln. Die erste Stichprobe enthält alle Länder aus der Tabelle COUNTRIES, die zweite - die Spalte mit den Ländern aus der vorherigen zusammengesetzten Abfrage.

In diesem Fall sieht der SQL-Code wie folgt aus:

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
       )


Der MQL5-Code sieht einfacher aus, da wir uns die Tatsache zunutze machen, dass die vorherige Abfrage zu unserer neuen Unterabfrage wird.

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


Nach Abschluss der Codeausführung erhalten wir folgende Einträge im Protokoll:

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 


Von allen Ländern haben also nur Italien und Spanien keine wichtigen Ereignisse. Anfragen über Länderereignisse in MQL5 wurden im Skript sRequest1.mq5 ausgeführt.


3.2.2 Stichprobe der BIP-Werte nach Ländern

In diesem Beispiel werden wir eine Datenbankabfrage durchführen, um eine Auswahl von BIP-Werten für verschiedene Länder zu erhalten. Als Wert des BIP nehmen wir den Parameter „Bruttoinlandsprodukt (BIP) q/q“ (für das 3. Quartal).

Es wird mehrere Proben geben, sodass die Abfrage zusammengesetzt sein wird.

Zunächst wollen wir herausfinden, in welchen Ländern es einen vierteljährlichen BIP-Indikator gibt.

Der SQL-Code sieht wie folgt aus:

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


Die MQL5-Implementierung sieht wie folgt aus (Skript 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();


Nachfolgend finden Sie einen Ausdruck aus dem Protokoll, nachdem die Abfrage ausgeführt wurde:

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 


Wie wir sehen können, gibt es den erforderlichen Indikator in 21 Ländern. Der Indikator wird in Indien nicht als globaler Indikator verwendet („Worldwide“).

Nun müssen wir eine Stichprobe von Indikatorwerten für das 3. Quartal erhalten und diese mit der ersten Auswahl nach Ereignis-ID verknüpfen.

Die SQL-Abfrage sieht wie folgt aus:

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


Was den MQL5-Code betrifft, so ist die verbundene Abfrage wie folgt implementiert:

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


Nach der Ausführung erscheinen die folgenden Zeilen im Protokoll:

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 


Es ist leicht zu erkennen, dass es in der Stichprobe mehrere Werte für einige Ereignisse mit der gleichen event_id gibt. Die Einträge 2-4 beziehen sich zum Beispiel auf den Parameter EU. Mehrere Zahlen des BIP wurden geschätzt, sodass es mehrere Parameterwerte gibt. Im Ergebnis enthält die endgültige Stichprobe 36 Einträge, was deutlich mehr ist als die Anzahl der Länder, für die der Parameter berechnet wurde.

Wenn wir eine Stichprobe erstellen wollen, indem wir nur die neuesten Werte für ein bestimmtes Ereignis abrufen, müssen wir in der Abfrage die Möglichkeit zum Gruppieren und Sortieren von Gruppenergebnissen hinzufügen. Dann erhalten wir die folgende zusammengesetzte SQL-Abfrage:

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)


Die Einträge werden nach der Spalte „event_id“ (Feld) gruppiert. Wenn es mehrere Einträge gibt, wird derjenige mit dem höchsten Wert in der Spalte „value_id“ (Feld) verwendet. Daher wird in diesem Fall nur einer der drei Einträge für die EU ausgewählt:

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


Infolgedessen erscheinen die folgenden Einträge im Protokoll:

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 


Nun sind 21 Einträge in der Stichprobe vorhanden. Schließlich müssen wir den Ländercode durch seinen Namen ersetzen. Ändern wir die vorherige SLQ-Abfrage wie folgt:

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


Wir implementieren auf dem Weg dorthin die folgende zusammengesetzte Abfrage in 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();


Das gewünschte Muster wird ins Journal ausgedruckt:

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 


Obwohl das Problem in mehreren Ansätzen gelöst wurde, war es durch die Möglichkeit, eine Abfrage in eine andere einzubinden, viel einfacher.


Schlussfolgerung

Ich hoffe, dass der Artikel das Interesse derjenigen Händler und Entwickler wecken wird, die makroökonomische Daten für ihre Strategien nutzen. Ich würde es aber wagen zu behaupten, dass auch keine Makro-Parameter den Aufbau einer guten Strategie ermöglichen. Sie können jedoch als Ergänzung zu den ursprünglichen Daten des neuronalen Netzes nützlich sein. 

Übersetzt aus dem Russischen von MetaQuotes Ltd.
Originalartikel: https://www.mql5.com/ru/articles/11977

Beigefügte Dateien |
CalendarDB.zip (52.66 KB)
Datenwissenschaft und maschinelles Lernen (Teil 10): Ridge-Regression Datenwissenschaft und maschinelles Lernen (Teil 10): Ridge-Regression
Die Ridge-Regression ist ein einfaches Verfahren zur Reduzierung der Modellkomplexität und zur Vermeidung einer Überanpassung, die bei einer einfachen linearen Regression auftreten kann.
Testen und Optimieren von Strategien für binäre Optionen in MetaTrader 5 Testen und Optimieren von Strategien für binäre Optionen in MetaTrader 5
In diesem Artikel werde ich Strategien für binäre Optionen in MetaTrader 5 überprüfen und optimieren.
Erstellen eines EA, der automatisch funktioniert (Teil 08): OnTradeTransaktion Erstellen eines EA, der automatisch funktioniert (Teil 08): OnTradeTransaktion
In diesem Artikel erfahren Sie, wie Sie das Ereignisbehandlungssystem nutzen können, um Probleme im Zusammenhang mit dem Auftragssystem schnell und effizient zu bearbeiten. Mit diesem System wird der EA schneller arbeiten, sodass er nicht ständig nach den benötigten Daten suchen muss.
Messen der Information von Indikatoren Messen der Information von Indikatoren
Maschinelles Lernen hat sich zu einer beliebten Methode für die Strategieentwicklung entwickelt. Während die Maximierung der Rentabilität und der Vorhersagegenauigkeit stärker in den Vordergrund gerückt wurde, wurde der Bedeutung der Verarbeitung der Daten, die zur Erstellung von Vorhersagemodellen verwendet werden, nicht viel Aufmerksamkeit geschenkt. In diesem Artikel befassen wir uns mit der Verwendung des Konzepts der Entropie zur Bewertung der Eignung von Indikatoren für die Erstellung von Prognosemodellen, wie sie in dem Buch Testing and Tuning Market Trading Systems von Timothy Masters dokumentiert sind.