
MQL5経済指標カレンダーを使った取引(第3回):通貨、重要度、時間フィルターの追加
はじめに
この記事では、以前のMetaQuotes Language 5 (MQL5)経済指標カレンダーに関する記事を基に、経済イベントをリアルタイムで表示するニュースダッシュボードパネルを開発しました。今回は、通貨、重要度、時間に関する特定のフィルターを実装し、このダッシュボードをさらに強化します。これにより、トレーダーは自分の戦略に最も関連性の高いニュースイベントに集中できるようになります。これらのフィルターにより、市場に影響を与える重要なイベントを絞り込み、意思決定を効率化し、取引の精度を向上させることができます。取り上げるトピックは次のとおりです。
これらの機能を追加することで、私たちのダッシュボードは、MQL5環境内でトレーダーのニーズに合わせたタイムリーで関連性の高い情報を提供できる強力なツールとなります。
経済指標カレンダーのフィルターの種類について
ダッシュボードの機能を向上させるためには、通貨、重要度、時間という各フィルタータイプの目的と利点を理解することが重要です。通貨フィルターを使用すると、取引中の通貨に特に影響を与える経済イベントを表示できます。これにより、オープンポジションに影響を及ぼす可能性のある関連イベントを簡単に特定できます。このフィルターは、取引ポートフォリオ内の通貨に絞ることで、情報過多を防ぎ、ダッシュボードを効率的に管理できます。MetaTrader 5取引端末では、[指標カレンダー]タブにマウスを合わせて右クリックし、優先通貨や国を選択することで、通貨ごとにニュースをフィルタリングできます。以下にイラストを示します。
重要度フィルターは、予想される影響の大きさに基づいてイベントを分類します。通常、重要度は低・中・高の3段階で定義されます。中央銀行の発表や失業率など、市場に大きな影響を与える可能性のある重要なイベントは、ボラティリティを引き起こすことがあります。重要度に基づいてイベントをフィルタリングすることで、取引において最も影響を与える可能性のある出来事を迅速に特定し、トレーダーの対応力を高めることができます。影響度に応じたニュースのフィルタリングは、[経済カレンダー]タブを右クリックし、優先度に応じて選択することでおこなうことができます。以下にイラストを示します。
最後に、時間フィルターを使用することで、関連する経済イベントの発生時間を指定できます。これは、特定の取引セッション中に取引をおこなったり、今後のニュースに備えたりする際に非常に便利です。このフィルターを使うと、次の1時間、1日、1週間など、設定した期間内に発生するイベントを確認できるため、取引戦略や時間帯に合わせたタイムラインが提供されます。これらのフィルターを組み合わせることで、経済ニュースデータを個別の取引ニーズに合わせてカスタマイズできるため、応答性と効率性に優れたMQL5ダッシュボードの基盤が作られます。
mql5でのフィルターの実装
MQL5 でフィルターを実装するには、まずグローバルスコープでブール変数を定義する必要があります。これらの変数は、通貨、重要度、および時間のフィルターを有効にするか無効にするかを制御します。これらをグローバルに定義することで、コード全体を通じてフィルターにアクセスして変更できるようになり、ニュースダッシュボードの動作に柔軟性がもたらされます。このステップでは、フィルターロジックを実装するための基盤が設定され、取引のニーズに応じてダッシュボードの機能をカスタマイズできるようになります。これを実現するために、次のようなロジックを使用します。
//--- Define flags to enable/disable filters bool enableCurrencyFilter = true; // Set to 'true' to enable currency filter, 'false' to disable bool enableImportanceFilter = true; // Set to 'true' to enable importance filter, 'false' to disable bool enableTimeFilter = true; // Set to 'true' to enable time filter, 'false' to disable
ここでは、enablecurrencyfilter、enableimportancefilter、enabletimefilterという3つのブール変数を定義します。これらは、通貨、重要度、および時間のそれぞれのフィルターを有効にするか無効にするかを制御するために使用します。各変数はデフォルト値のtrueに設定されています。つまり、デフォルトではすべてのフィルターがアクティブになっています。これらの値をfalseに変更することで、使用したくないフィルターを無効にすることができ、取引の好みに基づいてニュースダッシュボードの機能をカスタマイズできるようになります。
ここからは、有効なニュースイベントをカウントする際の初期化ロジックです。まず、通貨フィルターから始めます。最初に、フィルターを適用する通貨コードを定義する必要があります。以下のように定義します。
string curr_filter[] = {"AUD","CAD","CHF","EUR","GBP","JPY","NZD","USD"}; int news_filter_count = 0;
ここでは、文字列型配列「curr_filter」を定義します。この配列には、特定の通貨に基づいてニュースをフィルタリングするために使用する通貨ペアのリスト(「AUD」、「CAD」、「CHF」、「EUR」、「GBP」、「JPY」、「NZD」、「USD」)が含まれます。この配列は、ダッシュボードに表示されるニュースイベントを絞り込み、選択した通貨に関連するものだけに焦点を当てるのに役立ちます。また、news_filter_count変数も定義します。これは、選択した基準に一致するフィルタリングされたニュースイベントの数を追跡するために使用され、最も関連性の高い情報のみが表示されるようにします。次に、以下のようにフィルターロジックに移ります。
//--- Check if the event’s currency matches any in the filter array (if the filter is enabled) bool currencyMatch = false; if (enableCurrencyFilter) { for (int j = 0; j < ArraySize(curr_filter); j++) { if (country.currency == curr_filter[j]) { currencyMatch = true; break; } } //--- If no match found, skip to the next event if (!currencyMatch) { continue; } }
ここでは、イベントの通貨がcurr_filter配列内のいずれかの通貨と一致するかどうかを確認しますが、これはenableCurrencyFilterフラグで示されるように通貨フィルターが有効になっている場合のみです。フィルターが有効になっている場合は、forループを使用してcurr_filter配列をループし、各反復でイベントの通貨とフィルター内の通貨を比較します。
一致が見つかった場合は、currencyMatchフラグをtrueに設定し、breakでループを終了します。一致するものが見つからない場合(つまり、currencyMatchがfalseのままの場合)、continue文を使用して現在のイベントをスキップし、次のイベントに進み、関連するイベントのみが処理されるようにします。次に、同じロジックを使用して、重要度に基づいてイベントをフィルタリングします。
//--- Check importance level if importance filter is enabled bool importanceMatch = false; if (enableImportanceFilter) { for (int k = 0; k < ArraySize(allowed_importance_levels); k++) { if (event.importance == allowed_importance_levels[k]) { importanceMatch = true; break; } } //--- If importance does not match the filter criteria, skip the event if (!importanceMatch) { continue; } }
ここでは、イベントの重要度レベルを事前定義されたallowed_importance_levels配列に対してチェックしますが、これはenableImportanceFilterフラグで示されるように重要度フィルターが有効になっている場合のみです。フィルターが有効になっている場合は、forループを使用してallowed_importance_levels配列をループし、イベントの重要度と配列内のレベルを比較します。
一致が見つかった場合は、importanceMatchフラグをtrueに設定し、breakでループを終了します。一致が見つからない場合(つまり、importanceMatchがfalseのままの場合)、continue文を使用して現在のイベントをスキップし、必要な重要度レベルのイベントのみが処理されるようにします。次のように別の配列を使用して重要度レベルを定義しました。
// Define the levels of importance to filter (low, moderate, high) ENUM_CALENDAR_EVENT_IMPORTANCE allowed_importance_levels[] = {CALENDAR_IMPORTANCE_LOW, CALENDAR_IMPORTANCE_MODERATE, CALENDAR_IMPORTANCE_HIGH};
ここでは、すべての重要度レベルを追加しました。つまり、技術的には優先度に基づいてすべてのニュースを許可しますが、取引の決定に最適なものを選択できます。次に、時間フィルターの範囲を定義する必要があります。
//--- Define time range for filtering news events based on daily period datetime timeRange = PeriodSeconds(PERIOD_D1); datetime timeBefore = TimeTradeServer() - timeRange; datetime timeAfter = TimeTradeServer() + timeRange;
ニュースイベントをフィルタリングするために、日足期間に基づいて時間範囲を定義します。PeriodSeconds関数と定数PERIOD_D1を使用して、1日の秒数を取得し、それを「timeRange」というdatetime型変数に割り当てます。timeBeforeとtimeAfter変数は、TimeTradeServer関数を使用して現在のサーバー時間を取得し、その前後にtimeRangeをそれぞれ引き算および足し算することで、現在のサーバー時間を基準にした時間範囲を計算します。これにより、指定した時間範囲内(現在のサーバー時間の前後1日以内)のイベントのみが処理対象として考慮されます。必要に応じて、このロジックを調整してください。このロジックを元に、時間フィルターを適用することができます。
//--- Apply time filter and set timeMatch flag (if the filter is enabled) bool timeMatch = false; if (enableTimeFilter) { datetime eventTime = values[i].time; if (eventTime <= TimeTradeServer() && eventTime >= timeBefore) { timeMatch = true; //--- Event is already released } else if (eventTime >= TimeTradeServer() && eventTime <= timeAfter) { timeMatch = true; //--- Event is yet to be released } //--- Skip if the event doesn't match the time filter if (!timeMatch) { continue; } }
ここでは、イベントの時間が指定された時間範囲内にあるかどうかをチェックして時間フィルターを適用し、timeMatchフラグを使用してイベントが基準を満たしているかどうかを追跡します。enableTimeFilterがtrueの場合、まずvalues[i].time変数からイベントの時間を取得します。次に、イベントの時間が過去(現在のサーバー時間とtimeBeforeの間)か未来(現在のサーバー時間とtimeAfterの間)かを確認します。イベント時間がどちらかの範囲内にある場合、timeMatchフラグがtrueに設定され、イベントが時間フィルターに一致することが示されます。一致するものが見つからない場合は、continue文を使用してイベントをスキップします。
フィルターについては以上です。ここまで来れば、すべてのテストを通過し、いくつかのニュースイベントがあることになります。したがって、ニュースフィルターのカウントを1つ更新します。
//--- If we reach here, the currency matches the filter news_filter_count++; //--- Increment the count of filtered events
今回は選択されたすべてのイベントを考慮していないため、データ ホルダーセクションを作成するためにニュースフィルターカウントデータを使用します。これにより、ダッシュボード内で関連性のあるデータホルダーが十分に作成されます。
//--- Set alternating colors for each data row holder color holder_color = (news_filter_count % 2 == 0) ? C'213,227,207' : clrWhite; //--- Create rectangle label for each data row holder createRecLabel(DATA_HOLDERS+string(news_filter_count),62,startY-1,716,26+1,holder_color,1,clrNONE);
ここでは、行間の視覚的な区別を改善するために、各データ行ホルダーに交互の色を設定します。holder_colorは三項演算子を使用して決定されます。news_filter_countが偶数の場合(つまり、「news_filter_count % 2 == 0」)、色は明るい緑色(C'213,227,207')に設定され、奇数の場合は、色は白に設定されます。これにより、各行の色が交互に変わり、データが読みやすくなります。
次に、createRecLabel関数を使用して各データ行ホルダーの長方形ラベルを作成し、指定された座標に色付きの長方形を配置します。ラベルは、DATA_HOLDERSとnews_filter_countの文字列表現を組み合わせることで一意に識別され、各行に一意の名前が付けられ、長方形の寸法がコンテンツに合わせて設定されます。長方形の境界線の太さは1に設定され、塗りつぶしの色は交互のholder_colorに設定され、境界線の色は境界線の色なしのclrNONEに設定されています。
ただし、境界線を取り除くために、黄色で強調表示されているホルダーのy変位に1ピクセルを追加したことに注意してください。比較結果は以下のとおりです。
1ピクセル追加前
1ピクセル追加後
うまくいきました。次におこなう必要があるのは、フィルターが適用されたときにダッシュボードに表示されるニュースの合計を更新することです。
updateLabel(TIME_LABEL,"Server Time: "+TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS)+" ||| Total News: "+ IntegerToString(news_filter_count)+"/"+IntegerToString(allValues));
ここでは、updateLabel関数を使用して、現在のサーバー時間とフィルタリングされたニュースイベントの合計数を表示するラベルを更新します。TIME_LABELで識別されるラベルを、現在のサーバー時間とニュースイベントの数を組み合わせた新しい文字列で更新します。現在のサーバー時刻を取得するには、TimeCurrent関数を使用し、TIME_DATE|TIME_SECONDSフラグを指定したTimeToString関数を使用してフォーマットします。
次に、news_filter_countに保存されているフィルタリングされたニュースイベントの合計数を、allValuesで表される利用可能なニュースイベントの合計数とともに表示します。このラベルを更新することで、サーバー時間とニュースフィルターの状態の両方に関するリアルタイム情報が提供され、当社にとって重要な現在の市場ニュースを常に把握できるようになります。
ラベルを更新するために使用するカスタム関数のコードスニペットは次のとおりです。
//+------------------------------------------------------------------+ //| Function to create text label | //+------------------------------------------------------------------+ bool updateLabel(string objName,string txt) { // Reset any previous errors ResetLastError(); if (!ObjectSetString(0,objName,OBJPROP_TEXT,txt)) { Print(__FUNCTION__, ": failed to update the label! Error code = ", _LastError); return (false); } ObjectSetString(0, objName, OBJPROP_TEXT, txt); // Text displayed on the label // Redraw the chart to display the label ChartRedraw(0); return (true); // Label creation successful }
ここでは、チャート上の既存のラベルを更新するために使用するupdateLabel関数を定義します。この関数は、objName(ラベルオブジェクトの名前)とtxt(ラベルに表示されるテキスト)の2つのパラメータを取ります。まず、ResetLastError関数を使用して以前のエラーをリセットし、クリーンな状態を確保します。次に、ObjectSetString関数を使用して、指定された文字列「txt」でラベルのテキストを更新します。更新が失敗した場合は、Print関数を使用してエラーメッセージと_LastErrorから取得したエラーコードを出力し、falseを返します。
ラベルの更新が成功した場合は、ChartRedraw関数を呼び出してチャートを更新し、更新されたラベルを表示し、最後に操作が成功したことを示すtrueを返します。これは、チャート上のラベルの内容を動的に更新し、サーバー時間やニュースイベント数などの情報を柔軟に表示できる機能です。プログラムを実行すると、次のようになります。
この実装により、私たちにとって関連性のあるニュースのみを考慮し、他のニュースは無視することが確実になりました。また、選択したすべてのニュースのうち通過したニュースの合計も表示し、利用可能なニュースイベントと検討中のニュースイベントの両方を示します。フィルターの適用を担当する完全な初期化コードスニペットは次のとおりです。
string curr_filter[] = {"AUD","CAD","CHF","EUR","GBP","JPY","NZD","USD"}; int news_filter_count = 0; // Define the levels of importance to filter (low, moderate, high) ENUM_CALENDAR_EVENT_IMPORTANCE allowed_importance_levels[] = {CALENDAR_IMPORTANCE_LOW, CALENDAR_IMPORTANCE_MODERATE, CALENDAR_IMPORTANCE_HIGH}; //--- Loop through each calendar value up to the maximum defined total for (int i = 0; i < valuesTotal; i++){ MqlCalendarEvent event; //--- Declare event structure CalendarEventById(values[i].event_id,event); //--- Retrieve event details by ID MqlCalendarCountry country; //--- Declare country structure CalendarCountryById(event.country_id,country); //--- Retrieve country details by event's country ID MqlCalendarValue value; //--- Declare calendar value structure CalendarValueById(values[i].id,value); //--- Retrieve actual, forecast, and previous values //--- Check if the event’s currency matches any in the filter array (if the filter is enabled) bool currencyMatch = false; if (enableCurrencyFilter) { for (int j = 0; j < ArraySize(curr_filter); j++) { if (country.currency == curr_filter[j]) { currencyMatch = true; break; } } //--- If no match found, skip to the next event if (!currencyMatch) { continue; } } //--- Check importance level if importance filter is enabled bool importanceMatch = false; if (enableImportanceFilter) { for (int k = 0; k < ArraySize(allowed_importance_levels); k++) { if (event.importance == allowed_importance_levels[k]) { importanceMatch = true; break; } } //--- If importance does not match the filter criteria, skip the event if (!importanceMatch) { continue; } } //--- Apply time filter and set timeMatch flag (if the filter is enabled) bool timeMatch = false; if (enableTimeFilter) { datetime eventTime = values[i].time; if (eventTime <= TimeTradeServer() && eventTime >= timeBefore) { timeMatch = true; //--- Event is already released } else if (eventTime >= TimeTradeServer() && eventTime <= timeAfter) { timeMatch = true; //--- Event is yet to be released } //--- Skip if the event doesn't match the time filter if (!timeMatch) { continue; } } //--- If we reach here, the currency matches the filter news_filter_count++; //--- Increment the count of filtered events //--- Set alternating colors for each data row holder color holder_color = (news_filter_count % 2 == 0) ? C'213,227,207' : clrWhite; //--- Create rectangle label for each data row holder createRecLabel(DATA_HOLDERS+string(news_filter_count),62,startY-1,716,26+1,holder_color,1,clrNONE); //--- Initialize starting x-coordinate for each data entry int startX = 65; //--- Loop through calendar data columns for (int k=0; k<ArraySize(array_calendar); k++){ //--- Print event details for debugging //Print("Name = ",event.name,", IMP = ",EnumToString(event.importance),", COUNTRY = ",country.name,", TIME = ",values[i].time); //--- Skip event if currency does not match the selected country code // if (StringFind(_Symbol,country.currency) < 0) continue; //--- Prepare news data array with time, country, and other event details string news_data[ArraySize(array_calendar)]; news_data[0] = TimeToString(values[i].time,TIME_DATE); //--- Event date news_data[1] = TimeToString(values[i].time,TIME_MINUTES); //--- Event time news_data[2] = country.currency; //--- Event country currency //--- Determine importance color based on event impact color importance_color = clrBlack; if (event.importance == CALENDAR_IMPORTANCE_LOW){importance_color=clrYellow;} else if (event.importance == CALENDAR_IMPORTANCE_MODERATE){importance_color=clrOrange;} else if (event.importance == CALENDAR_IMPORTANCE_HIGH){importance_color=clrRed;} //--- Set importance symbol for the event news_data[3] = ShortToString(0x25CF); //--- Set event name in the data array news_data[4] = event.name; //--- Populate actual, forecast, and previous values in the news data array news_data[5] = DoubleToString(value.GetActualValue(),3); news_data[6] = DoubleToString(value.GetForecastValue(),3); news_data[7] = DoubleToString(value.GetPreviousValue(),3); //--- Create label for each news data item if (k == 3){ createLabel(ARRAY_NEWS+IntegerToString(i)+" "+array_calendar[k],startX,startY-(22-12),news_data[k],importance_color,22,"Calibri"); } else { createLabel(ARRAY_NEWS+IntegerToString(i)+" "+array_calendar[k],startX,startY,news_data[k],clrBlack,12,"Calibri"); } //--- Increment x-coordinate for the next column startX += buttons[k]+3; } //--- Increment y-coordinate for the next row of data startY += 25; //Print(startY); //--- Print current y-coordinate for debugging } //Print("Final News = ",news_filter_count); updateLabel(TIME_LABEL,"Server Time: "+TimeToString(TimeCurrent(), TIME_DATE|TIME_SECONDS)+" ||| Total News: "+ IntegerToString(news_filter_count)+"/"+IntegerToString(allValues));
うまくいきました。最終的には、プログラムがチャートから削除されたときにダッシュボードを削除して、クリーンな環境を残す必要があります。これをより専門的に簡単に実現するには、すべての制御ロジックを追加する関数を定義します。
//+------------------------------------------------------------------+ //| Function to destroy the Dashboard panel | //+------------------------------------------------------------------+ void destroy_Dashboard(){ //--- Delete main rectangle panel ObjectDelete(0, MAIN_REC); //--- Delete first sub-rectangle in the dashboard ObjectDelete(0, SUB_REC1); //--- Delete second sub-rectangle in the dashboard ObjectDelete(0, SUB_REC2); //--- Delete header label text ObjectDelete(0, HEADER_LABEL); //--- Delete server time label text ObjectDelete(0, TIME_LABEL); //--- Delete label for impact/importance ObjectDelete(0, IMPACT_LABEL); //--- Delete all objects related to the calendar array ObjectsDeleteAll(0, ARRAY_CALENDAR); //--- Delete all objects related to the news array ObjectsDeleteAll(0, ARRAY_NEWS); //--- Delete all data holder objects created in the dashboard ObjectsDeleteAll(0, DATA_HOLDERS); //--- Delete all impact label objects ObjectsDeleteAll(0, IMPACT_LABEL); //--- Redraw the chart to update any visual changes ChartRedraw(0); }
ここでは、カスタム関数「destroy_Dashboard」を定義します。この関数は、チャート上のダッシュボードパネル用に作成されたすべての要素を完全に削除し、チャートを初期状態に戻すために使用します。これには、ダッシュボード内で使用されている各オブジェクト、ラベル、およびホルダーの削除が含まれます。まず、ダッシュボードのプライマリコンテナを表すMAIN_RECを試用してObjectDelete関数を呼び出して、メインパネルの長方形を削除します。次に、ダッシュボードのさまざまなセクションを整理するために使用したSUB_REC1やSUB_REC2などのサブ長方形を削除します。
これに続いて、ダッシュボードヘッダー(HEADER_LABEL)、サーバー時間(TIME_LABEL)、影響レベル(IMPACT_LABEL)などの情報を表示するラベルを削除します。これらの各ラベルは、チャート上に表示されるテキスト情報がすべてクリアされるように削除されています。次に、カレンダーとニュースデータに関する情報をそれぞれ保存しているARRAY_CALENDARとARRAY_NEWS内のすべてのオブジェクトを削除します。このアクションはObjectsDeleteAll関数を使用して実行します。これにより、これらの配列に関連付けられた動的に作成されたオブジェクトをすべてクリアできます。
次に、ダッシュボードにデータポイントを表示する個々の行またはコンテナを表すDATA_HOLDERSに関連するすべてのオブジェクトを削除し、その後にIMPACT_LABELインスタンスを削除する別の呼び出しを行って、視覚的な要素が残らないようにします。
最後に、ChartRedraw関数を呼び出します。これにより、チャートが更新され、ダッシュボードの残りの部分がクリアされ、さらに描画したりダッシュボードをリセットしたりするための空白のキャンバスが提供されます。この関数は基本的にダッシュボードの表示全体を解体し、プログラムを削除した後、必要に応じてチャートを新しく更新したり、その他の視覚要素を追加したりできるように準備します。最後に、ダッシュボードの削除を実行するために、OnDeinitイベントハンドラで関数を呼び出します。
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason){ //--- destroy_Dashboard(); }
OnDeinitイベントハンドラでカスタム関数を呼び出した後、チャートからダッシュボードを削除するようにします。ダッシュボードにフィルターを追加するために必要なのはこれだけです。
結論
結論として、通貨、重要度、時間に基づいて最も関連性の高いニュースイベントのみを表示するための重要なフィルタリング機能を統合することで、MQL5経済指標カレンダーダッシュボードを強化することに成功しました。これらのフィルターにより、より洗練され、焦点を絞ったインターフェースが実現し、特定の取引戦略や目標に適した経済イベントに集中できるようになります。
このフィルターを活用してダッシュボードを改良したことで、情報に基づいた意思決定を支援する、より強力で効率的なツールとなりました。次回は、カレンダーダッシュボードのロジックにライブ更新機能を追加し、この基盤をさらに拡張することで、MQL5ダッシュボード内で最新の経済ニュースを常に直接更新できるようにします。
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/16380




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