
MQL5クックブック - マクロ経済イベントデータベース
はじめに
この記事では、マクロ経済のカレンダーイベントを説明するデータをグループ化して管理する方法に焦点を当てます。
現代の世界では、情報の流れがあらゆる場所に行き渡っています。そのため、イベントを分析する際にはビッグデータを処理する必要があります。この記事は、コンテンツではなく形成に関連する問題を大部分カバーしていますが、データの正しい編成と構造化は、これらのデータが情報に変わるという事実に大きく貢献しているようです。
これらのタスクをSQLiteを使用して解決します。開発者は、MQL5から直接SQLiteを処理するためのサポートをビルド2265(2019年12月6日)に追加しました。その前に、たとえば、「SQLとMQL5:SQLiteデータベースとの連携」稿で説明されているように、さまざまなコネクタを使用する必要がありました。
1. ドキュメントと追加資料
ドキュメント、特にデータベース処理に関するセクションをざっと見てみましょう。開発者は26のネイティブ関数を提供しています。
- DatabaseOpen()
- DatabaseClose()
- DatabaseImport()
- DatabaseExport()
- DatabasePrint()
- DatabaseTableExists()
- DatabaseExecute()
- DatabasePrepare()
- DatabaseReset()
- DatabaseBind()
- DatabaseBindArray()
- DatabaseRead()
- DatabaseReadBind()
- DatabaseFinalize()
- DatabaseTransactionBegin()
- DatabaseTransactionCommit()
- DatabaseTransactionRollback()
- DatabaseColumnsCount()
- DatabaseColumnName()
- DatabaseColumnType()
- DatabaseColumnSize()
- DatabaseColumnText()
- DatabaseColumnInteger()
- DatabaseColumnLong()
- DatabaseColumnDouble()
- DatabaseColumnBlob()
最近追加された統計および数学関数のブロックもあります。「SQLite:MQL5でのSQLデータベースのネイティブな処理」稿は、この機能を学習するための出発点として役立ちます。
2.CDatabaseクラス
データベースの扱いに便利なCDatabaseクラスを作成しましょう。まず、クラス構成について説明します。次に、例を使用してその動作を確認します。
CDatabaseクラスのデータメンバーには、次のものが含まれます。
- m_name:データベースファイル名(拡張子付き)
- m_handle:データベースハンドル
- m_flags:フラグの組み合わせ
- m_table_names:表名
- m_curr_table_name:現在の表名
- m_sql_request_ha:最後のSQLクエリハンドル
- m_sql_request:最後のSQLクエリ
メソッドに関しては、いくつかのグループに分けます。
- データベースを処理するためのネイティブ関数を含むメソッド(API MQL5関数)
- 表を処理するメソッド
- リクエストを処理するメソッド
- ビューを操作するためのメソッド
- データメンバー値を取得するためのメソッド(getメソッド)
SQLiteには、単純なものから複雑なものまで、複数のリクエストフォームがあります。私の目的は、そのようなフォームごとにCDatabaseクラスにカスタムメソッドを作成することではありません。 クラスに特定のリクエスト用のメソッドがない場合、汎用のCDatabase::Select()メソッドを使用してリクエストを作成できます。
次に、CDatabaseクラスの機能を使用する例を見てみましょう。
2.1 データベースの作成
1_create_calendar_db.mq5スクリプトを使用して最初のカレンダーデータベースを作成しましょう。 スクリプトのコードは数行のみです。
//--- 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(); } //+------------------------------------------------------------------+
スクリプトを実行すると、データベースファイルtest_calendar_db.sqliteが%MQL5\Files\Databasesに表示されることがわかります(図1)。
図1:test_calendar_db.sqliteデータベースファイル
このファイルをコードエディタで開くと、データベースが空であることがわかります(図2)。
図2:test_calendar_dbデータベース
2.2 表の作成
データベースに入力してみましょう。これをおこなうには、COUNTRIES表を作成します。この表には、後でクエリによってカレンダーイベントが処理される国のリストを入力します。2_create_countries_table.mq5スクリプトが仕事をします。
//--- include #include "..\CDatabase.mqh" //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- open a database CDatabase db_obj; string file_name="Databases\\test_calendar_db.sqlite"; uint flags=DATABASE_OPEN_READWRITE; if(!db_obj.Open(file_name, flags)) { ::PrintFormat("Failed to open a calendar database \"%s\"!", file_name); db_obj.Close(); return; } //--- create a table string table_name="COUNTRIES"; string params[]= { "COUNTRY_ID UNSIGNED BIG INT PRIMARY KEY NOT NULL,", // 1) country ID "NAME TEXT," // 2) country name "CODE TEXT," // 3) country code "CONTINENT TEXT," // 4) country continent "CURRENCY TEXT," // 5) currency code "CURRENCY_SYMBOL TEXT," // 6) currency symbol "URL_NAME TEXT" // 7) country URL }; if(!db_obj.CreateTable(table_name, params)) { ::PrintFormat("Failed to create a table \"%s\"!", table_name); db_obj.Close(); return; } db_obj.Close(); } //+------------------------------------------------------------------+
スクリプトを実行すると、COUNTRIES表がデータベースに表示されていることがわかります(図3)。
図3: 空のCOUNTRIES表
2.3 表への記入
新しい表にデータを入力しましょう。これをおこなうには、CiCalendarInfoクラスの機能を使用します。クラスの詳細については、「MQL5クックブック - 経済指標カレンダー」稿を参照してください。このタスクは3_fill_in_countries_table.mq5スクリプトによって実行されます。
//--- include #include "..\CalendarInfo.mqh" #include "..\CDatabase.mqh" //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- open a database CDatabase db_obj; string file_name="Databases\\test_calendar_db.sqlite"; uint flags=DATABASE_OPEN_READWRITE; if(!db_obj.Open(file_name, flags)) { db_obj.Close(); return; } //--- open a table string table_name="COUNTRIES"; if(db_obj.SelectTable(table_name)) if(db_obj.EmptyTable()) { db_obj.FinalizeSqlRequest(); string col_names[]= { "COUNTRY_ID", "NAME", "CODE", "CONTINENT", "CURRENCY", "CURRENCY_SYMBOL", "URL_NAME" }; //--- fill in the table CiCalendarInfo calendar_info; if(calendar_info.Init()) { MqlCalendarCountry calendar_countries[]; if(calendar_info.GetCountries(calendar_countries)) { if(db_obj.TransactionBegin()) for(int c_idx=0; c_idx<::ArraySize(calendar_countries); c_idx++) { MqlCalendarCountry curr_country=calendar_countries[c_idx]; string col_vals[]; ::ArrayResize(col_vals, 7); col_vals[0]=::StringFormat("%I64u", curr_country.id); col_vals[1]=::StringFormat("'%s'", curr_country.name); col_vals[2]=::StringFormat("'%s'", curr_country.code); col_vals[3]="NULL"; SCountryByContinent curr_country_continent_data; if(curr_country_continent_data.Init(curr_country.code)) col_vals[3]=::StringFormat("'%s'", curr_country_continent_data.ContinentDescription()); col_vals[4]=::StringFormat("'%s'", curr_country.currency); col_vals[5]=::StringFormat("'%s'", curr_country.currency_symbol); col_vals[6]=::StringFormat("'%s'", curr_country.url_name); if(!db_obj.InsertSingleRow(col_names, col_vals)) { db_obj.TransactionRollback(); db_obj.Close(); return; } db_obj.FinalizeSqlRequest(); } if(!db_obj.TransactionCommit()) ::PrintFormat("Failed to complete transaction execution, error %d", ::GetLastError()); } //--- print if(db_obj.PrintTable()<0) ::PrintFormat("Failed to print the table \"%s\", error %d", table_name, ::GetLastError()); } } db_obj.Close(); } //+------------------------------------------------------------------+
COUNTRIES表データをログに出力します。
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
MetaEditorでは、表は次のようになります(図4)。
図4: 入力済みのCOUNTRIES表
2.4 表列の選択
COUNTRIES表のデータを処理しましょう。次の列を選択するとします。
- "COUNTRY_ID"
- "COUNTRY_NAME"
- "COUNTRY_CODE"
- "COUNTRY_CONTINENT"
- "CURRENCY"
次の方法で4_select_some_columns.mq5スクリプトを使用してSQLクエリを作成します。
//--- 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(); } //+------------------------------------------------------------------+
クエリを出力すると、次のようになります。
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
明らかに、選択は並び替えなしでおこなわれました。
2.5 並び替えされた表列の選択
表のデータを「COUNTRY_ID」列で並べ替えてみましょう。このリクエストは、5_select_some_sorted_columns.mq5スクリプトで次のように実装されています。
//--- include #include "..\CDatabase.mqh" //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { //--- open a database CDatabase db_obj; string file_name="Databases\\test_calendar_db.sqlite"; uint flags=DATABASE_OPEN_READONLY; if(!db_obj.Open(file_name, flags)) { db_obj.Close(); return; } //--- check a table string table_name="COUNTRIES"; if(db_obj.SelectTable(table_name)) { string col_names_to_select[]= { "COUNTRY_ID", "NAME", "CODE", "CONTINENT", "CURRENCY" }; string ord_names[1]; ord_names[0]=col_names_to_select[0]; if(!db_obj.SelectFromOrderedBy(col_names_to_select, ord_names)) { db_obj.Close(); return; } //--- print the SQL request if(db_obj.PrintSqlRequest()<0) ::PrintFormat("Failed to print the SQL request, error %d", ::GetLastError()); db_obj.FinalizeSqlRequest(); } db_obj.Close(); } //+------------------------------------------------------------------+
クエリ実行の結果がログに表示されます。
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
スクリプトは正しく機能します。「COUNTRY_ID」列は0から始まり、999で終わります。
2.6 指定した表の列のグループ化された結果の選択
6_select_some_grouped_columns.mq5スクリプトを使用して、大陸ごとにグループ化された国名を取得しましょう。タスクは、大陸の各行に含まれる国の数を取得することです。国はNAME列から選択されます。スクリプトを実行すると、次の行がログに表示されます。
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」には国が最も多く含まれています(9か国)が、「Africa」と「South America」にはそれぞれ1か国しかありません。また、「World」もあります。
2.7 指定された表列の一意の値を選択する
7_select_distinct_columns.mq5スクリプトを使用して、CURRENCY列の一意の値を収集します。同じ通貨を使用している国があります。繰り返しを取り除くには、スクリプトを実行します。次の結果が表示されます。
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
したがって、カレンダーには合計18の通貨のイベントと、すべての通貨に適用される1つのイベントグループがあります。
グループ化された結果を選択する方法と一意の値を選択する方法が類似していることは容易にわかります。これを例で示しましょう。
8_compare_grouped_and_distinct_columns.mq5 スクリプトは、ログに次の結果を表示します。
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
最初のメソッドのグループ化列(フィールド)としてCONTINENT列を定義したため、メソッドは同じ内容の結果を返しました。興味深いことに、最初の方法でも選択内容が並び替えされています。
2.8 指定された表列の順序付けされた一意の値の選択
CURRENCY列の値は、7_select_distinct_columns.mq5スクリプトによって並び替えされていない方法で表示されました。並び替えで選択してみましょう(9_select_sorted_distinct_columns.mq5スクリプト)。列「COUNTRY_ID」を並び替え基準にします。ログ操作の結果、次のようになります。
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
これですべての通貨が並び替えされました。デフォルトでは、並び替えは昇順で実行されます。
2.9 条件による表列の選択
前に、表の列を選択するためのSQLクエリを作成しました。条件が満たされたときに列を取得できるようにしましょう。IDが392以上840以下の国を選択するとします。このタスクは10_select_some_columns_where.mq5スクリプトによって解決されます。
スクリプトを実行すると、ログに次のように表示されます。
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
つまり、サンプルは国コード392で始まり、840で終わります。
2.10 条件による並び替え済み表列の一部の選択
前の問題をもっと複雑にしてみましょう。サンプルに並び替え基準を追加してみましょう。これはその大陸に属している国です。現在のタスクは11_select_some_sorted_columns_where.mq5スクリプトで解決されます。実行すると、ログに次の行が表示されます。
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
その結果、大陸「Africa」が大陸のリストの最初に来るので、「South Africa」がサンプルの最初になります。
2.11 条件による表列の一部の更新
選択した列の行を更新するタスクに直面しているとします。また、前提条件を満たしてからおこなう必要があります。
アジア諸国を取り上げて、CURRENCY列とCURRENCY_SYMBOL列の値をリセットしてみましょう。このタスクは12_update_some_columns.mq5スクリプトによって実行されます。
実行の結果、次の表が得られます。
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 表の行の置換と追加
表の作業を続けましょう。では、選択した表のいくつかの行を置き換えてみましょう。
CURRENCY_SYMBOL列の現在のシンボル「Mex$」を「Mexico」の「Peso mexicano」に置き換える必要があるとします。このタスクを13_replace_some_rows.mq5スクリプトに任せます。
COUNTRIES表の現在のバージョンでは、メキシコには次のエントリがあります。
COUNTRY_ID | NAME | CODE | CONTINENT | CURRENCY | CURRENCY_SYMBOL | URL_NAME |
---|---|---|---|---|---|---|
484 | Mexico | MX | North America | MXN | Mex$ |
|
表内のこの行を置き換えるには、選択した行に一意の値を設定する必要があります。そうしないと、SQLiteは何を置き換えたいのか理解できません。
この値が国の名前(NAME列)になると仮定しましょう。次に、置換関数はコードで次のように表されます。
//--- 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; }
スクリプトを実行すると、次のエラーが発生します。
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
明らかに、NOT NULL制約に違反しています。問題は、最初に表を作成するときに、COUNTRY_ID列にnullを含めることができないと指定されたことです。したがって、この列に値を追加する必要があります。行が半分空にならないように、すべての列に値を追加しましょう。
//--- 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; }
これで、スクリプトは問題なく動作します。次のエントリがログに表示されます。
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
メキシコに関するデータを含む行がない場合は、単純に追加されることに注意してください。つまり、置換操作は表の行を追加する操作でもあります。
2.13表の行の一部を削除する
表の行数を増やすのではなく減らす方法を見てみましょう。これをおこなうには、リクエストに応じて選択した表からアジア関連の行を削除する14_delete_some_rows.mq5スクリプトを作成します。
スクリプトを実行した後、最終表を表示します。
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
アジア関連の行は見つかりませんでした。
2.14表への列の追加
表に新しい列を追加することも、かなり一般的なタスクです。
COUNTRIES表を拡張し、カレンダーに含まれるマクロ経済イベントの数を含む列を追加する必要があるとします。
このタスクは15_add_new_column.mq5スクリプトによって実行されます。
スクリプトを実行したら、表を確認します(図5)。新しい列EVENTS_NUMが追加されました。
図5 COUNTRIES表の新しいEVENTS_NUM列
2.15表内の列の名前変更
列の名前変更は、CDatabase::RenameColumn(const string _curr_name, const string _new_name)によっておこなわれます。現在および新しい列名をパラメーターとして設定します。16_rename_column.mq5スクリプトは、EVENTS_NUM列名をEVENTS_NUMBERに置き換えます。
図6:COUNTRIES表のEVENTS_NUMBER列の名前が変更されました
表は次のようになります(図6)。
2.16行の連結
単一の表内でサンプリング結果を連結する必要があるとします。これは、CDatabase::Union()メソッドによって実現できます。このタスクは、17_union_some_columnsによって実行されます。MQ5スクリプト。
EUROPEAN_COUNTRIESとNORTH_AMERICAN_COUNTRIESの2つの表があるとします。最初の表はヨーロッパ諸国を特徴とし、2番目の表は北米諸国を含みます。まず、行を連結する表を作成しましょう。各表は、COUNTRIES表からの結果の選択になります。これは、コードでは次のようになります。
//--- 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();
スクリプトの実行中に、ログに次のエントリが記録されます。
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
結果のサンプルには、ヨーロッパと北アメリカの国が含まれます。
2.17サンプルの違い
2つのサンプルがあるとします。2番目のサンプルには存在しない最初のサンプルのエントリを見つける必要があります。これは、CDatabase::Except()メソッドによって実現できます。
COUNTRIES表とEUROPEAN_COUNTRIES表を例に取りましょう。最初の表にEXCEPT演算子を適用した場合に残る国を見てみましょう。
ソリューションは18_except_some_columns.mq5スクリプトによって提供されます。
スクリプトの実行結果として、次の行がログに表示されます。
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
ご覧のとおり、サンプルにはヨーロッパの国は含まれていません。アジアの国も既に削除されたため、欠落しています。
2.18サンプル交差点
それでは、サンプルに共通する特徴を見てみましょう。言い換えれば、タスクはサンプルの共通行を見つけることです。
まず、COUNTRIES表を更新して、アジア諸国を含む元の形式に戻します。
「id」、「name」、および「currency」列を持つ2つの一時表を作成します。最初の列にはCOUNTRY_ID列の値が578を超えない国が含まれ、2番目の列には同じ列の値が392以上の国が含まれます。
//--- create temporary tables string table1_name, table2_name, sql_request; table1_name="Table1"; table2_name="Table2"; sql_request="SELECT COUNTRY_ID AS id, NAME AS name, CURRENCY " "as currency FROM COUNTRIES " "WHERE COUNTRY_ID<=578"; if(!db_obj.CreateTableAs(table1_name, sql_request, true, true)) { db_obj.Close(); return; } db_obj.FinalizeSqlRequest(); //--- print the temporary table string temp_col_names[]= {"*"}; if(db_obj.SelectTable(table1_name, true)) if(db_obj.SelectFrom(temp_col_names)) { ::Print(" \nTable #1: "); db_obj.PrintSqlRequest(); db_obj.FinalizeSqlRequest(); } sql_request="SELECT COUNTRY_ID AS id, NAME AS name, CURRENCY " "as currency FROM COUNTRIES " "WHERE COUNTRY_ID>=392"; if(!db_obj.CreateTableAs(table2_name, sql_request, true, true)) { db_obj.Close(); return; } db_obj.FinalizeSqlRequest(); //--- print the temporary table if(db_obj.SelectTable(table2_name, true)) if(db_obj.SelectFrom(temp_col_names)) { ::Print(" \nTable #2: "); db_obj.PrintSqlRequest(); db_obj.FinalizeSqlRequest(); }
19_intersect_some_columns.mq5スクリプトでCDatabase::Intersect()メソッドの機能を使用しましょう。その結果、ログに次の行が表示されます。
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
スクリプトは正しく機能しました。国の最小ID値が392で、最大ID値が578である国のリストを取得しました。
2.19 ビューの作成
ビューとは仮想の表のようなものです。便利なのは、他の表から選択したデータを表示できることです。
boolCDatabase::CreateView()メソッドとboolCDatabase::CreateViewWhere()メソッドを使用してビューを作成します。最初のメソッドはある種の無条件のビューを作成し、2番目のメソッドは指定された条件に従ってビューを作成します。
次の例を考えてみましょう。COUNTRIES表があります。新しい仮想表のNAME、CONTINENT、CURRENCY列によってすべての国を選択する必要があるとします。
20_create_view.mq5スクリプトでこの問題を解決しましょう。その結果が「All_countries」ビューです(図7)。
図7:「All_countries」ビュー
例を複雑にして、ヨーロッパの国のみを選択してみましょう。21_create_view_where.mq5スクリプトがこれをおこないます。その結果、ヨーロッパの国のみを含む仮想表ができました(図8)。
図8: 「European」ビュー
ビュー内の行は追加、削除、更新できないため、ビューは本格的な表ではありませんが、表自体の関係に影響を与えることなく名前を変更しながら、複雑なクエリの結果を簡単に集計し、個々の列を選択するために使用できます。
2.20 ビューの削除
CDatabase::DropView()メソッドを使用して、以前に作成したビューを削除できます。
このメソッドは、対応する、表を削除するDropTable()メソッドと似ています。前の例では、ビューが作成される前に呼び出されたのはビュー削除メソッドでした。
ここで、IF EXISTS構造について簡単に説明します。この構成で存在しないビューを削除しようとすると、メソッドは「true」を返し、それ以外の場合は「false」を返します。
スクリプト22_drop_view.mq5がどのように機能するか見てみましょう。
//--- drop a view string table_name="COUNTRIES"; if(db_obj.SelectTable(table_name)) for(int idx=0; idx<2; idx++) { string view_name=::StringFormat("European%d", idx+1); bool if_exists=idx; if(db_obj.DropView(view_name, if_exists)) ::PrintFormat("A view \"%s\" has been successfully dropped!", view_name); db_obj.FinalizeSqlRequest(); }
まず、IF EXISTSを呼び出さずに、存在しない「European_countries1」ビューを削除しようとします。その結果、エラー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!
その後、スクリプトはIF EXISTSを使用して、存在しない「European_countries2」ビューを削除しようとします。実際には削除がおこなわれなくても、2番目のビューの削除は成功します。
2.21 表の名前変更
表自体の名前を変更するタスクに直面しているとしましょう。これをおこなうには、CDatabase::RenameTable()メソッドに目を向けます。名前は23_rename_table.mq5スクリプトによって変更されます。
図9:COUNTRIES1表の名前変更
その結果、現在の表の名前はCOUNTRIES1になります(図9)。
3.マクロ経済イベントのデータベース
このセクションでは、カレンダーに含まれるマクロ経済イベントのリレーショナルデータベースの作成を開始することを提案します。
まずは将来のデータベースを構成する表構造を作りましょう。カレンダー構造については、「MQL5クックブック - 経済指標カレンダー」稿で既に考慮されています。したがって、私たちの場合、データベース表を作成してそれらの関係を設定するのは非常に簡単です。
3.1 表とリレーショナル接続
データベースには、次の3つのソース表が含まれます。
- 国
- イベント
- EVENT_VALUES
表間の関係を図10に示します。
図10: Calendar_DBデータベース内の表間の接続の構造
COUNTRIES表は、EVENTS表の親表になります。後者は、前者の子になります。
COUNTRIES表の主キーはCOUNTRY_ID列(フィールド)です。画像では、先頭に「+」記号が付いています。EVENTS表の場合、キーはEVENT_ID列ですが、COUNTRY_ID列は外部外部キーです。構造では、先頭に「#」記号が付きます。
EVENTS表はEVENT_VALUES表の親表になり、2番目の表は最初の表の子表になります。
EVENT_VALUES表では、主キーはVALUE_ID列(フィールド)であり、外部キーはEVENT_IDです。
キーは、上記の表間の関係を実装するために正確に必要です。この関係は、データベース内のデータの整合性に貢献します。
3つの表間の関係は、1対多の形式(1..*)です。それらを解読することは難しくないと思います。国と出来事の間の最初のつながりは、次のように表すことができます。1つの国には多くのマクロ経済イベントがあり、1つのイベントには1つの国しかありません。イベントとイベント値の間の2番目の関係は、1つのイベントには多くの値があるが、どの値にも1つのイベントしかないと説明できます。
コードに移りましょう。sCreateAndFillCalendarDB.mq5スクリプトには、次の段階があります。
- カレンダーデータベースの作成
- データベース表の作成
- 表への入力
たとえば、EVENTS表がどのように作成されるかを見てみましょう。この表を作成するための最終的なクエリは次のようになります。
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 )
外部キーが作成される文字列は特に重要です。FOREIGN KEY(COUNTRY_ID)行は、表にCOUNTRY_IDフィールドによる外部キーがあることを意味します。REFERENCES COUNTRIES(COUNTRY_ID)構造は、COUNTRIES親表を参照するために使用されます。
ON UPDATE CASCADEおよびON DELETE CASCADE式は、関連する行が親表から削除または変更されると、子表の行も削除または変更されることを意味します。
表への入力に関しては、以下はCOUNTRIES表が入力されているコードのブロックです。
//--- Table 1 MqlCalendarCountry calendar_countries[]; table_name="COUNTRIES"; if(db_obj.SelectTable(table_name)) if(db_obj.EmptyTable()) { db_obj.FinalizeSqlRequest(); string col_names[]= { "COUNTRY_ID", // 1 "NAME", // 2 "CODE", // 3 "CONTINENT", // 4 "CURRENCY", // 5 "CURRENCY_SYMBOL",// 6 "URL_NAME" // 7 }; CiCalendarInfo calendar_info; if(calendar_info.Init()) { if(calendar_info.GetCountries(calendar_countries)) { if(db_obj.TransactionBegin()) for(int c_idx=0; c_idx<::ArraySize(calendar_countries); c_idx++) { MqlCalendarCountry curr_country=calendar_countries[c_idx]; string col_vals[]; ::ArrayResize(col_vals, 7); col_vals[0]=::StringFormat("%I64u", curr_country.id); col_vals[1]=::StringFormat("'%s'", curr_country.name); col_vals[2]=::StringFormat("'%s'", curr_country.code); col_vals[3]="NULL"; SCountryByContinent curr_country_continent_data; if(curr_country_continent_data.Init(curr_country.code)) col_vals[3]=::StringFormat("'%s'", curr_country_continent_data.ContinentDescription()); col_vals[4]=::StringFormat("'%s'", curr_country.currency); col_vals[5]=::StringFormat("'%s'", curr_country.currency_symbol); col_vals[6]=::StringFormat("'%s'", curr_country.url_name); if(!db_obj.InsertSingleRow(col_names, col_vals)) { db_obj.TransactionRollback(); db_obj.Close(); return; } db_obj.FinalizeSqlRequest(); } if(!db_obj.TransactionCommit()) ::PrintFormat("Failed to complete transaction execution, error %d", ::GetLastError()); } //--- print if(db_obj.PrintTable()<0) ::PrintFormat("Failed to print the table \"%s\", error %d", table_name, ::GetLastError()); } }
まず、表をさらに操作するには、CDatabase::SelectTable()メソッドを使用して表を選択する必要があります。ここで、さらなる処理のために::PositionSelect()ネイティブ関数を使用して取引ポジションが選択される方法との類似性を引き出すことができます。
次に、CDatabase::EmptyTable()メソッドが事前に表をクリアします。
次に、ループ内の国を調べて、列ごとに表を埋めます。
- "COUNTRY_ID",
- "COUNTRY_NAME",
- "COUNTRY_CODE",
- "CONTINENT",
- "CURRENCY",
- "CURRENCY_SYMBOL",
- "URL_NAME"
最後の行は、CDatabase::InsertSingleRow()メソッドによって表に挿入されます。表への入力には、トランザクションメカニズムが必要です。詳細については「トランザクションをDatabaseTransactionBegin()/DatabaseTransactionCommit()にラップ」セクションを参照してください。
3つの表を埋めた結果、次の結果が得られました。COUNTRIES表には23エントリが含まれ、EVENTS表には1500エントリが含まれ、EVENT_VALUES表には158,696エントリが含まれます(図11)。
図11:入力されたEVENT_VALUES表
データを取得したので、クエリの作成を開始できます。
3.2 データベースクエリ
概して、すべてのデータベースクエリは次の2つのグループに分けることができます。
1)データベースからデータを受け取るリクエスト
2)データベース内のデータを変更するクエリ
まず、カレンダーデータベースから情報を取得する例を扱いましょう。
3.2.1 国別のサンプル数
データベースに各国のマクロ経済イベントの数を尋ねることから始めましょう。「EVENTS」表を参照して、次のクエリを作成します。
SELECT COUNTRY_ID AS id, COUNT(EVENT_ID) AS events_num FROM EVENTS GROUP BY COUNTRY_ID
MQL5コードでは、そのようなリクエストは次のように実装されます。
//--- 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();
結果は、端末ログに表示されるCOUNTRY_IDソース列とCOUNT(EVENT_ID)ソース列による次の選択になります。
sRequest1 (EURUSD,H1) #| id events_num sRequest1 (EURUSD,H1) --+--------------- sRequest1 (EURUSD,H1) 1| 0 7 sRequest1 (EURUSD,H1) 2| 36 85 sRequest1 (EURUSD,H1) 3| 76 55 sRequest1 (EURUSD,H1) 4| 124 74 sRequest1 (EURUSD,H1) 5| 156 40 sRequest1 (EURUSD,H1) 6| 250 43 sRequest1 (EURUSD,H1) 7| 276 62 sRequest1 (EURUSD,H1) 8| 344 26 sRequest1 (EURUSD,H1) 9| 356 57 sRequest1 (EURUSD,H1) 10| 380 52 sRequest1 (EURUSD,H1) 11| 392 124 sRequest1 (EURUSD,H1) 12| 410 36 sRequest1 (EURUSD,H1) 13| 484 47 sRequest1 (EURUSD,H1) 14| 554 82 sRequest1 (EURUSD,H1) 15| 578 47 sRequest1 (EURUSD,H1) 16| 702 27 sRequest1 (EURUSD,H1) 17| 710 54 sRequest1 (EURUSD,H1) 18| 724 39 sRequest1 (EURUSD,H1) 19| 752 59 sRequest1 (EURUSD,H1) 20| 756 40 sRequest1 (EURUSD,H1) 21| 826 115 sRequest1 (EURUSD,H1) 22| 840 247 sRequest1 (EURUSD,H1) 23| 999 82
「id」列は国名ではなく国IDであるため、選択内容はあまり読みにくくなっています。国名はCOUNTRIES表にあります。
国の名前と国のイベント数を取得するには、複合クエリ(クエリ内のクエリ)を作成する必要があります。
このような複合クエリの最初のバージョンは次のようになります。
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
このオプションは、最初に作成したクエリを使用します。しかし、それは別のクエリの一部になり、その形式がサブクエリの形式に変わりました。
リクエストの2番目のバージョンは、CTEの形式で実装できます。
WITH ev_cnt AS ( SELECT COUNTRY_ID AS id, COUNT(EVENT_ID) AS events_num FROM EVENTS GROUP BY COUNTRY_ID ) SELECT c.NAME AS country, ev.events_num AS events_number FROM COUNTRIES c INNER JOIN ev_cnt AS ev ON c.COUNTRY_ID = ev.id
MQL5コードでは、複合クエリは次のように実装されます。
//--- 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();
表式(CTE)は次のように実装されます。
//--- 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();
どちらのオプションでも、次のクエリ結果がログに出力されます。
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
カレンダーが米国のイベントに最大の注意を払っていることは容易にわかります。247のイベントが含まれています。
タスクを少し複雑にして、特定の国で発生した重要なイベントの数を計算する列をサンプルに追加してみましょう。重要度はIMPORTANCE列で定義されます。High値を持つイベントのみを選択します。
まず、EVENTS表を操作してみましょう。ここでは、2つのサンプルを作成する必要があります。最初のサンプルは、国別のイベント数のカウントです。このタスクは上記で既に完了しています。2番目のサンプルは、国ごとの重要なイベントの数です。最後に、2つのサンプルを組み合わせる必要があります。
クエリのSQLコードは次のようになります。
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
MQL5の実装に関しては、コードは次のようになります。
//--- 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();
その結果、次のログエントリが取得されます。
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
最終的な選択では、「id」列を「country」に置き換えるだけです。
複合クエリをもう一度作成しましょう。その部分が以前に書かれたという事実を利用します。最後に、「imp_events_number」列の値の降順でサンプルを並べ替えます。複合クエリは次のようになります。
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
MQL5コードでは、リクエストは次のように実装されます。
//--- 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();
これで、目的のサンプルがログに取得されます。
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
サンプルからわかるように、米国には最も重要なイベントが20件あります。英国は2位で13件です。3位はEU(11件)が占めています。日本は6位で7件です。
クエリを使用して、重要なイベントがまったくない国を見つけてみましょう。これをおこなうには、2つのサンプルの違いを見つける必要があります。最初のサンプルには、COUNTRIES表から取得されたすべての国が含まれますが、2番目のサンプルには、前の複合クエリからの国を含む列が含まれます。
この場合、SQLコードは次のようになります。
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 )
前のクエリが新しいサブクエリになるという事実を利用するため、MQL5コードはより単純に見えます。
//--- 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();
コードの実行が完了すると、ログに次のエントリが表示されます。
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
したがって、すべての国の中で、重要なイベントがないのはイタリアとスペインだけです。MQL5の国別イベントに関するリクエストは、sRequest1.mq5スクリプトで実行されました。
3.2.2 国別GDP値のサンプル
この例では、さまざまな国のGDP値の選択を取得するデータベースクエリを作成します。GDPの値として、「国内総生産(GDP)q/q」というパラメーターを使用します(第3四半期)。
いくつかのサンプルがあるため、クエリは複合になります。
まず、四半期ごとのGDP指標がある国の経済を調べてみましょう。
SQLコードは次のようになります。
SELECT COUNTRY_ID, EVENT_ID FROM EVENTS WHERE (NAME LIKE 'GDP q/q' AND SECTOR = 'Gross Domestic Product')
MQL5の実装は次のようになります(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();
以下は、クエリが実行された後のログからの出力です。
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
ご覧のとおり、必要な指標は21か国に存在します。この指標は、インドではグローバル(「Worldwide」)として使用されていません。
次に、第3四半期の指標値のサンプルを取得し、それをイベントIDによる最初の選択に関連付ける必要があります。
SQLクエリは次のようになります。
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' )
MQL5コードに関しては、複合クエリは次のように実装されます。
//--- 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();
実行後、次の行がログに表示されます。
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
同じevent_idを持ついくつかのイベントのサンプルに複数の値があることは簡単にわかります。たとえば、エントリ2~4はEUパラメータを参照しています。GDPはいくつかの測定値で推定されているため、いくつかのパラメータ値があります。その結果、最終的なサンプルには36のエントリが含まれており、これはパラメーターが計算された国の数を明らかに上回っています。
特定のイベントの最新の値のみを取得してサンプルを作成する必要がある場合は、グループ結果をグループ化および並び替えする機能をクエリに追加する必要があります。次に、次の複合SQLクエリを取得します。
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)
エントリは、「event_id」列(フィールド)によってグループ化されます。複数のエントリがある場合は、「value_id」カラム(フィールド)で最大値のものを使用します。したがって、この場合、EUの3つのエントリのうち1つだけが選択されます。
country_id | event_id | value_id | period | time | actual |
---|---|---|---|---|---|
999 | 999030016 | 158838 | 2022.07.0100:00 | 2022.12.0712:00 | 0.3 |
その結果、次のエントリがログに表示されます。
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
現在、サンプルには21のエントリがあります。最後に、国コードをその名前に置き換える必要があります。前のSLQクエリを次のクエリに変更しましょう。
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
途中で次の複合クエリを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();
希望するサンプルが操作ログに出力されます。
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
問題は複数の方法で解決されましたが、あるクエリを別のクエリに含めることができるため、はるかに簡単になりました。
結論
この記事が、マクロ経済データを使用して戦略を作成するトレーダーや開発者の関心を引くことを願っています。また、優れた戦略を構築するためのマクロパラメータは存在しないことをあえて提案したいと思います。ただし、それらは元のニューラルネットワークデータへの追加として役立つ場合があります。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/11977



- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索