English Русский Deutsch
preview
MetaTrader 5とMQL5経済指標カレンダー:ニュースを再現性のあるトレードシステムに変える方法

MetaTrader 5とMQL5経済指標カレンダー:ニュースを再現性のあるトレードシステムに変える方法

MetaTrader 5 |
30 8
MetaQuotes
MetaQuotes

はじめに

現代のニューストレーダーが抱える主な問題は、ツールが分散していることと、アルゴリズムに基づく体系的な取引ワークフローが存在しないことです。ニュースサイトを閲覧するためのWebブラウザと、実際に取引をおこなうMetaTrader 5ターミナルの間で注意を切り替え続けるのは非常に困難です。

ニューストレーダーの一般的なワークフローは次のようになります。ニュースカレンダーを素早くブラウザで開き、イベントに変更がないか確認する → 直近のイベントを評価し、何をどのように取引するかを判断する → MetaTrader 5ターミナルへ移動し、保留注文(未決注文)を設定する、あるいはニュース発表を待ちながらリアルタイムで判断を下す。このような流れでは、トレーダーはしばしば「状況把握の途切れ」を経験します。その結果、ニュースへの反応が遅れ、最終的には損失につながります。

ニューストレードを、明確なルールと再現可能な結果、自動テストを備えた「工学的な課題」として扱いたいと思いませんか?本記事の目的は、MetaTrader 5向けニュースレイヤーの実用的なアーキテクチャを示すことです。具体的には、単一データソースの構築、カレンダーAPIの正しい利用方法、フィルタリングおよびキャッシュ機構、テスター向け履歴イベントのリソース化、ライブ環境とテスター環境の自動切り替えを扱います。

トレーダーが抱える主な問題

図1:手動トレーダーの最大の問題はツールの分断化である


手動のニューストレードは時代遅れです。

まず、外部要因に依存し、体系化されていないニュース戦略は、そのままではテストできません。トレード戦略の成功の半分は、過去データにおけるパフォーマンス検証に関係しています。戦略をテストできないということは、意思決定が主観的になることを意味します。その戦略は仮説のまま残り、検証のために数か月、あるいは数年もの時間を費やすことになります。

次に、手動トレードはスケーリングが非常に困難です。不安定で収益が不規則なビジネスを拡大しようとしても、問題が悪化するだけです。明確な構造化、システム化、最適化がなければ、スケーリングについて考えること自体が無意味です。

第三に、ニュースへの反応の遅れは手動トレードにおける大きな問題点です。たとえば、外国為替(FX)トレーダーが雇用統計(NFP)を取引しているとします。NFPデータは通常、月に一度発表されます。もし気を取られて発表を見逃してしまえば、利益を得る機会を逃してしまいます。このような状況は多くのトレーダーにとって身近なものです。

結論として、再現性のあるニューストレードを実現する唯一の方法は自動化です。

反応比較

図2:ロボットは常により速い


MetaTrader 5内蔵の経済指標カレンダー:信頼できる単一のデータソース

ニューストレードをアルゴリズム化し、その結果としてヒストリカルテストを可能にするためには、MetaTrader 5に標準搭載された当社独自の経済カレンダーと、MQL5 API経由のニュースアクセスを活用します。これにより、ニューストレードは属人的な判断から検証可能なアルゴリズム運用へと変わります。リアルタイムイベントだけでなく、オフラインテスト用の過去のイベントデータも利用可能です。

表1:

MetaTrader 5に組み込まれている内蔵カレンダーの特長

パラメータ
アクセススピード
ニュースをターミナルへ読み込んだ後は100ms未満
統合 ネイティブ対応:ターミナルコアレベル + MQL API
テスト 完全対応:ニュースをターミナルへダウンロード後、ファイル、リソース、SQLite経由でストラテジーテスターからアクセス可能
信頼性 高い

MetaTrader 5には優れたストラテジーテスターが搭載されています。高速でマルチアセットに対応し、ローカルネットワークおよびグローバルネットワーク上のコンピュータを活用したテストや最適化が可能です。経済指標ニュースを利用したトレードシステムを、ぜひ過去データでバックテストしてみてください。これによって、トレード手法に対する考え方が大きく変わるかもしれません。


MetaTrader 5経済指標カレンダー関数:MQL5 APIの概要

手動分析からアルゴリズム分析への移行は、まずデータアーキテクチャを理解することから始まります。MQL5において、経済指標カレンダーは単なる表形式データではなく、ネイティブAPIを通じてアクセス可能な構造化データベースです。本記事では、イベントを正しく取得する方法、EventとValueの違い、時刻同期が戦略の正確性にとって重要である理由を解説します。

MQL5の経済指標カレンダー機能は、複数の主要関数によって構成されています。それぞれの関数は異なる役割を持っています。重要なのは、経済指標カレンダーのすべてのデータを一度に取得できる「万能関数」は存在しないという点です。実際の運用では、複数の関数を組み合わせて利用する必要があります。

  • CalendarValueHistory:初期読み込み用の主要ツール。指定した期間におけるイベント値の配列を取得します。これはエキスパートアドバイザー(EA)初期読み込み用の重量級関数であり、過去データの取得、今後数日〜1週間分のイベントデータ取得などをおこないます。
  • CalendarValueLast:リアルタイム稼働EA向けの主要関数。前回リクエスト以降に変更または追加された値のみを取得します。この仕組みはchange_idメカニズムによって実現されています。これにより、毎ティックごとにデータ配列全体を要求することなく、通信量とサーバー負荷を削減できます。
  • CalendarEventByCountry:指定した国に関連するイベント情報を取得します。ISO 3166-1 alpha-2に従って指定されたコードで特定される特定の国に対するイベント説明のリストを返します。フィルタ構築に必要です(たとえば、「US」(USA)、「RU」(ロシア)、「CA」(カナダ)などのイベントのみを表示する場合など)。
  • CalendarEventByCurrency:通貨ごとのすべてのイベント情報を取得します。「USD」「EUR」などのコードで指定された特定の通貨に対するイベント説明のリストを返します。
  • CalendarCountryById:idによって国のプロパティを取得します。
  • CalendarEventById:idによってイベントのプロパティを取得します。
  • CalendarValueById:idによって特定の値を取得します。

データ構造体:カレンダーMQL5 APIが返す値

経済指標カレンダーAPIのすべての関数は、構造体の配列または単一の構造体変数のいずれかを返します。以下に、構造体とそのフィールドを完全に列挙します。

イベント情報:CalendarEventByIdCalendarEventByCountryCalendarEventByCurrency関数で使用されます。

struct MqlCalendarEvent
  {
   ulong                               id;                    // event ID
   ENUM_CALENDAR_EVENT_TYPE            type;                  // event type from the ENUM_CALENDAR_EVENT_TYPE enumeration
   ENUM_CALENDAR_EVENT_SECTOR          sector;                // sector an event is related to
   ENUM_CALENDAR_EVENT_FREQUENCY       frequency;             // event frequency (periodicity)
   ENUM_CALENDAR_EVENT_TIMEMODE        time_mode;             // event time mode
   ulong                               country_id;            // country ID
   ENUM_CALENDAR_EVENT_UNIT            unit;                  // economic indicator value's unit of measure
   ENUM_CALENDAR_EVENT_IMPORTANCE      importance;            // event importance
   ENUM_CALENDAR_EVENT_MULTIPLIER      multiplier;            // economic indicator value multiplier
   uint                                digits;                // number of decimal places
   string                              source_url;            // URL of a source where an event is published
   string                              event_code;            // event code
   string                              name;                  // event text name in the terminal language (in the current terminal encoding)
  };


国情報:CalendarCountryByIdおよびCalendarCountries関数で使用されます。

struct MqlCalendarCountry
  {
   ulong                               id;                    // country ID (ISO 3166-1)
   string                              name;                  // country text name (in the current terminal encoding)
   string                              code;                  // country code name (ISO 3166-1 alpha-2)
   string                              currency;              // country currency code
   string                              currency_symbol;       // country currency symbol
   string                              url_name;              // country name used in the mql5.com website URL
  };


イベント値:CalendarValueByIdCalendarValueHistoryByEventCalendarValueHistoryCalendarValueLastByEventCalendarValueLast関数で使用されます。

struct MqlCalendarValue
  {
   ulong                               id;                    // value ID
   ulong                               event_id;              // event ID
   datetime                            time;                  // event date and time
   datetime                            period;                // event reporting period
   int                                 revision;              // revision of the published indicator relative to the reporting period
   long                                actual_value;          // actual value in ppm or LONG_MIN if the value is not set
   long                                prev_value;            // previous value in ppm or LONG_MIN if the value is not set
   long                                revised_prev_value;    // revised previous value in ppm or LONG_MIN if the value is not set
   long                                forecast_value;        // forecast value in ppm or LONG_MIN if the value is not set
   ENUM_CALENDAR_EVENT_IMPACT          impact_type;           // potential impact on the currency rate
   //--- functions for checking the values
   bool                         HasActualValue(void) const;   // returns 'true' if actual_value is set
   bool                         HasPreviousValue(void) const; // returns 'true' if prev_value is set
   bool                         HasRevisedValue(void) const;  // returns 'true' if revised_prev_value is set
   bool                         HasForecastValue(void) const; // returns 'true' if forecast_value is set
   //--- functions for getting values
   double                       GetActualValue(void) const;   // return actual_value or nan if the value is not set
   double                       GetPreviousValue(void) const; // return prev_value or nan if the value is not set
   double                       GetRevisedValue(void) const;  // returns revised_prev_value or nan if the value is not set
   double                       GetForecastValue(void) const; // returns forecast_value or nan if the value is not set
  };

注記:

なお、MqlCalendarValue構造体は、actual_value、forecast_value、prev_value、revised_prev_valueの各フィールドから値を確認し取得するためのメソッドを提供します。これらのフィールドには値が入っていない場合もあります。たとえば、actual_valueフィールドは、ニュースがまだ発表されていないため空になっていることがあります。そのため、値を取得する最も適切な方法は、構造体自体のメソッドを使って確認し、取得することです。

これらの構造体は、以下の関係によって相互に関連付けられています。

カレンダー関係

図3: カレンダー構造の関係


MqlCalendarCountry構造体は、国IDを介してMqlCalendarEventとリンクされています。この関係は「1対多(1..*)」です。

MqlCalendarEvent構造体は、イベントIDを介してMqlCalendarValueとリンクされています。この関係は「1対多(1..*)」です。


ニュースの発表時刻とサーバー時刻

経済指標カレンダーを扱うすべての関数は、トレードサーバー時間TimeTradeServerを使用します。つまり、MqlCalendarValue構造体の時刻およびCalendarValueHistoryByEvent()、CalendarValueHistory関数の入力時刻は、ユーザーのローカル時間ではなく、取引サーバーのタイムゾーンで設定されます。

時刻変換は不要です。MqlCalendarValue::periodの時刻フィールドは、TimeCurrent()やTimeTradeServer関数で取得した時刻と同じサーバー時間系で比較できます。テスター環境では、TimeTradeServer()関数はヒストリカルデータと同一のモデル時刻を返します。「ニュース30分前」といった時間ウィンドウのロジックは、リアルタイムとヒストリーの両方で同じように機能します。ブローカーが夏時間・冬時間の切り替えを考慮している場合、カレンダーもそれに自動的に対応します。


実例:本日(当日)のイベント一覧の取得

//+------------------------------------------------------------------+
//| Get calendar values for the current day                          |
//+------------------------------------------------------------------+
void GetTodayUSD_Events()
 {
//--- define the period boundaries in server time
  datetime server_now = TimeTradeServer();
  datetime day_start  = server_now - (server_now % 86400);
  datetime day_end    = day_start + 86400;

  MqlCalendarValue    values[];
  MqlCalendarEvent    event;
  MqlCalendarCountry  country;

//--- request values only for USD
  if(CalendarValueHistory(values, day_start, day_end, NULL, "USD"))
   {
    Print("  Events received for USD: ", ArraySize(values));

    //--- iterate over the array of values
    for(int i = 0; i < ArraySize(values); i++)
     {
      //--- get event description
      if(CalendarEventById(values[i].event_id, event))
      {
        //--- get country description
        if(CalendarCountryById(event.country_id, country))
        {
          Print("✅ Event #", i);
          Print("Event ID:       ", values[i].event_id);

          Print("Event name: ", event.name);
          Print("Sector:           ", event.sector);
          Print("Source:         ", event.source_url);

          Print("Country name:  ", country.name);
          Print("Country URL:       ", country.url_name);

          Print("Time:            ", TimeToString(values[i].time, TIME_DATE | TIME_SECONDS));
          Print("Impact:          ", values[i].impact_type);

          // CHECK AND OUTPUT VALUES
          if(values[i].HasActualValue())
            Print("Actual:             ", values[i].GetActualValue());

          if(values[i].HasRevisedValue())
            Print("Revised:     ", values[i].GetRevisedValue());

          if(values[i].HasForecastValue())
            Print("Forecast:          ", values[i].GetForecastValue());

          if(values[i].HasPreviousValue())
            Print("Previous:       ", values[i].GetPreviousValue());
        }
      }
     }
   }
  else
   {
    int error = GetLastError();
    if(error == 0)
     {
      Print("❌ CalendarValueHistory: No Events");
     }
    else
     {
      Print("❌ Error CalendarValueHistory: ", error);
     }
   }
 }
//+------------------------------------------------------------------+

この関数は、USD通貨に関する当日のイベント一覧と、MQL APIのカレンダーから取得した構造体の主要フィールドの内容を表示します。本記事に付属しているGetTodayEvents-S.mq5に完全なスクリプトコードが含まれています。

関数の実行結果は、MetaTrader 5ターミナルの[ツールボックス]→[エキスパート]タブで確認できます。USDについて2件のイベントが取得されていることが分かります。リクエスト時点では、これらのイベントはまだ発生しておらず(ニュースは未発表)、そのためMqlCalendarValue::actual_valueフィールドには値が入っていません。HasActualValue関数はfalseを返します。

これらのイベント種別では、HasForecastValue()で確認されるMqlCalendarValue::forecast_valueフィールドも存在しません(値を持ちません)。他のイベントでは、actual_value、forecast_value、prev_value、revised_prev_valueの4つすべてのフィールドが存在しない場合もあります。

  Received events for USD:2件
✅ Event #0
Event ID:            840220005
Event name:      3-month treasury bills auction
Sector:              1
Source:              https://home.treasury.gov/
Country name:   USA
Country URL:     united-states
Time:                2026.04.20 18:30:00
Impact:             0
Previous:           3.62
✅ Event #1
Event ID:           840220006
Event name:      6-month treasury bills auction
Sector:              1
Source:              https://home.treasury.gov/
Country name:   USA
Country URL:     united-states
Time:                2026.04.20 18:30:00
Impact:             0
Previous:           3.61

提供コードの説明:

まず、指定した時間範囲内のすべてのイベントについて、USD通貨フィルタ付きで値の配列を取得します。次にループ処理で配列を走査し、各イベントのevent_id(MqlCalendarValue::event_id)をキーとしてCalendarEventById関数でイベント詳細を取得します。その後、MqlCalendarEvent::country_idを使いCalendarCountryById関数で国情報を取得します。

CalendarValueHistory ()関数がfalseを返しているにもかかわらずGetLastError()が0の場合、それは指定条件に該当するイベントが存在しないことを意味します。


カレンダー処理におけるエラー処理と制限

リモートデータを扱う際には、接続の中断やアクセス制限のリスクがあります。カレンダー関数は失敗時にfalseまたは0を返します。原因を特定するにはGetLastErrorを使用する必要があります。カレンダーモジュールには専用のエラーコード群が定義されています。

エラーコード

  • ERR_CALENDAR_TIMEOUT (5200):サーバー応答待機時間切れ。ネットワーク障害またはサーバー過負荷。対策:5〜10秒待って再試行。
  • ERR_CALENDAR_NO_DATA (5201):カレンダーデータ未ロード。非同期初期化中。対策:1〜2秒待って再試行。
  • ERR_CALENDAR_INVALID_DATE (5202):日付範囲不正(例:開始日 > 終了日)。対策:ロジック修正(再試行しても無意味)。
  • ERR_CALENDAR_INVALID_COUNTRY (5203):国コード不正。パラメータにエラー。対策:コードを確認(たとえば、「USA」ではなく「US」)。
  • ERR_CALENDAR_TOO_MANY_REQUESTS (5204):リクエスト過多。重大なエラー。対策:リクエスト間隔を増やす。

リクエスト制限について

MetaTrader 5ターミナルが接続するサーバーは過負荷防止のため制限を設けています。EAがOnTick()内で毎ティックCalendarValueHistory()を呼び出すような実装では、エラー5204が発生し、一時的にカレンダーアクセスがブロックされます。 推奨される方法は、OnInitで必要データを一度だけ読み込むことです。

リアルタイム更新にはCalendarValueLastを使用し、change_idを保持することで差分のみを取得できます。 更新はOnTimerで5〜10分間隔でおこなうのがベストプラクティスです。

カレンダーの読み込み時に発生する可能性のある問題への対処例を見てみましょう。

ターミナル(コールドスタート時)およびEAを起動した直後は、カレンダーはまだ利用可能な状態になっていません。データはバックグラウンドでサーバーから読み込まれます。そのため、OnInit()の最初の行でCalendarValueHistory関数を呼び出すと、高い確率でエラー5201(データなし)が発生します。この問題に対処するには、カレンダーの準備完了を確認するためのポーリング機構を実装する必要があります。

実践例:エラー処理を備えたカレンダーデータ読み込み関数

//+------------------------------------------------------------------+
//| Calendar loading function                                        |
//+------------------------------------------------------------------+
bool LoadCalendar(MqlCalendarValue& values[], const datetime from, const datetime to, const string country_code = NULL, const string currency = NULL, const int max_retries = 5)
 {
  int retry_count = 0;

  while(retry_count < max_retries)
   {
    ResetLastError();
    //--- download attempt
    if(CalendarValueHistory(values, from, to, country_code, currency))
      return true; // Success

    int error = GetLastError();

    //--- in case of "No data" (5201) or "Timeout" (5200) error — wait and repeat
    if(error == 5201 || error == 5200)
     {
      retry_count++;
      Sleep(1000); // 1 second pause before repeating
      continue;
     }

    //--- if the error is critical (for example, an invalid date), interrupt the download immediately
    Print("❌ Critical Calendar Error: ", error);
    return false;
   }

  Print("❌ Failed to load calendar after ", max_retries, " attempts.");
  return false;
 }
//+------------------------------------------------------------------+

提供コードの説明:

5201 (No data)および5200 (Timeout)エラーが発生する可能性を考慮してください。これらは回復可能なエラーです。そのため、1〜5秒間待機した後に再度データ取得を試みるように処理してください。一方で、回復不能なエラーが発生した場合は、ただちにダウンロード処理を中止する必要があります。回復不能なエラーには、無効な日付範囲、誤った通貨コードや国コードの指定などが含まれます。完全なスクリプトコードは、本記事に添付されているGetTodayEvents-S.mq5ファイルに掲載されています。


制限回避と応答速度の最大化のため、OnTimer内ではchange_idメカニズムを使用するべきです。起動時にはイベント履歴全体を読み込み、最後に取得したchange_idを保存しておきます。その後、タイマー処理ではCalendarValueLast関数を使用して新しいデータのみを取得します。サーバーは変更があったデータだけを返し、変更がない場合はfalseを返します。これにより、過去のデータを毎回転送する無駄がなくなり、通信量やサーバー負荷を削減できます。

実践例:エラー処理を備えたカレンダーデータ更新関数

//+------------------------------------------------------------------+
//| Timer: incremental update                                        |
//+------------------------------------------------------------------+
void OnTimer()
 {
  if(!is_initialized)
    return;

  MqlCalendarValue updates[];
  ResetLastError();

//--- API automatically updates last_change_id by reference
  if(!CalendarValueLast(last_change_id, updates,
                        (InpCountryCode == "") ? NULL : InpCountryCode,
                        (InpCurrency    == "") ? NULL : InpCurrency))
   {
    int err = GetLastError();
    // 0 = SUCCESS/NO_NEW_DATA, 5402 = ERR_CALENDAR_NO_CHANGES
    if(err != 0 && err != 5402)
      Print("🔴️ CalendarValueLast error: ", err);
    return;
   }

  int cnt = ArraySize(updates);
  if(cnt == 0)
    return;

  Print("🟢 Received ", cnt, " updates. New change_id: ", last_change_id);
  if(InpPrintChanges)
    ArrayPrint(updates);
  SyncCache(updates);
 }
//+------------------------------------------------------------------+
//| Cache synchronization                                            |
//+------------------------------------------------------------------+
void SyncCache(const MqlCalendarValue &updates[])
 {
  int upd_cnt  = ArraySize(updates);
  int cache_sz = ArraySize(calendar_cache);

  for(int u = 0; u < upd_cnt; u++)
   {
    bool found = false;
    for(int c = 0; c < cache_sz; c++)
     {
      if(calendar_cache[c].id == updates[u].id)
       {
        calendar_cache[c] = updates[u];
        found = true;
        break;
       }
     }
    if(!found)
     {
      ArrayResize(calendar_cache, cache_sz + 1);
      calendar_cache[cache_sz] = updates[u];
      cache_sz++;
      total_events++;
     }
   }
 }
//+------------------------------------------------------------------+

提供コードの説明:

イベントの増分更新は、OnTimer()タイマーのイベントハンドラによって実行されます。カレンダーAPIのCalendarValueLast()関数を呼び出し、新しいイベントが検出された場合は、事前に読み込まれているMqlCalendarValue構造体配列内の対応する要素を更新し、その内容をターミナルのジャーナルへ出力します。 更新対象のイベントが既存の配列内に見つからない場合は、そのイベントを新しい要素として配列へ追加します。

完全なスクリプトコードは、本記事に添付されているCalendarEventMonitor-EA.mq5に含まれています。


イベントのフィルタリング:全体から重要なものへ

なぜフィルタリングが必要なのか

経済指標カレンダーでは、1日に60〜90件ものイベントが公開されます。これは、市場への直接的な影響がほとんどない小規模な経済指標、祝日、要人発言などを含む大量の情報が絶えず流れている状態に似ています。それらすべてを取引対象にすると、過剰売買となり、資金を失う可能性が高くなります。ニュースを利用するアルゴリズムトレーダーの目的は、市場を本当に動かす3〜5件程度の重要イベントだけを抽出することです。

アルゴリズムニューストレードにおけるフィルタリングは、自動売買が利用可能なレベルまでシグナル対ノイズ比を高める作業に相当します。MQL5カレンダーAPIでは、この処理はMqlCalendarEventおよびMqlCalendarValue構造体配列に対して適用される多段階のフィルタリングシステムとして実装されます。

フィルタリング基準

市場が反応するのはニュースの発表そのものではなく、実際の結果、予想値、マクロ経済的な影響度の差異です。影響度の低いイベント(MqlCalendarValue::impact_type < 3)は、市場参加者やアルゴリズムによって無視されることが少なくありません。

フィルタリングをおこなわない場合、次のような問題が発生します。

  • 二次的な統計指標による誤ったシグナル発生
  • ボラティリティが低いにもかかわらずスプレッドだけが広い時間帯での取引
  • 不要な判定処理によるEAロジックの肥大化

フィルタリングの目的は、データ量を約90%削減し、指定した通貨と時間帯において、ENUM_CALENDAR_EVENT_IMPORTANCE::CALENDAR_IMPORTANCE_HIGHに該当する高重要度イベントだけを残すことです。 

ここでは、リアルタイム環境とストラテジーテスター環境の両方で同じように機能する、信頼性の高いフィルタを構築する方法を見ていきます。

多段階フィルタリングシステム

ターミナルからダウンロードした「生の」イベントデータは、未精製の鉱石のようなものです。その中には、ほとんど意味のない統計データ、市場が休場となる祝日情報、実際には取引判断に利用できないイベントなど、多数の不要情報が含まれています。

この大量のデータから有効なシグナルだけを抽出するには、多段階フィルタリングシステムが必要です。イベントフィルタは「ふるい」として機能し、生データを通過させながら、通貨、重要度、イベントコード、時間帯などの条件に一致するイベントだけを出力します。

効率的なフィルタは階層構造を持つべきです。まず地域や通貨による大まかな絞り込みをおこない、その後で時間帯などの詳細条件による微調整をおこないます。

ニュースMQL5 APIの重要な特徴として、MqlCalendarValue構造体にはcurrency_idフィールドおよびcountry_idフィールドが存在しません。この構造体に格納されるのは、event_id、time、指標値、および影響度の種類のみです。これはフィルタリングにどのような影響を与えるのでしょうか。

通貨によるフィルタリングはAPIリクエストの段階で実行されます。CalendarValueHistory(..., NULL, "USD")を呼び出すと、ターミナル自体がUSD以外のイベントを除外します。受け取る配列は、すでにUSDによってフィルタリングされた状態になっています。したがって、リアルタイム処理においてcurrency_idを確認する必要はありません。時間、重要度、および予想値の有無や重要性によるフィルタリングだけで十分です。

レベル1:通貨フィルタ

最初の障壁はイベントの地理的対象です。EURUSDを取引している場合、EAはユーロ圏(EUR)および米国(USD)に影響を与えるイベントのみに反応すべきです。フィルタリングは、取引対象銘柄の通貨コードを指定してイベントを取得することで実現されます。クロス通貨ペア(たとえば「GBPJPY」)の場合は、両方の通貨(「GBP」と「JPY」)に加え、「USD」のイベントも取得する必要があります。

レベル2:イベントの重要性

すべてのニュースは、経済、ひいては価格への影響度という点で重要性が異なります。たとえば、消費者物価指数(CPI)は市場を100ポイント動かすことがありますが、ZEW景況感指数は10ポイント程度しか動かさない場合があります。

MQL5 APIでは、重要度のレベルをENUM_CALENDAR_EVENT_IMPORTANCE列挙型によって表します。

enum ENUM_CALENDAR_EVENT_IMPORTANCE
{
   CALENDAR_IMPORTANCE_NONE,      // importance level is not set
   CALENDAR_IMPORTANCE_LOW,       // low importance
   CALENDAR_IMPORTANCE_MODERATE,  // medium importance
   CALENDAR_IMPORTANCE_HIGH       // high importance
};

ニュースEAは、流動性の低いニュースによる誤検出を避けるため、HIGH未満の重要度のイベントはすべて無視すべきです。

レベル3:イベントコード

重要度の高いイベントの中にも例外があります。たとえば、ECBやIMFの要人発言は重要イベントとして分類されることがありますが、具体的な経済指標の発表と比較すると、アルゴリズムによる処理はより困難です。そのため、イベントコードによる選別が必要になります。MqlCalendarEvent::event_codeフィールドには、一意の識別子(たとえば「NONFARM」、「CPI」、「GDP)が格納されています。私たちは、アンケート調査や要人発言ではなく、経済指標の数値発表に該当するイベントのみを選択します。

最初の3段階のチェックをすべて通過したイベントだけが、結果配列へコピーされ、実際の取引に利用されます。

フィルタレベル

図4:ニューストレード成功の鍵となる多段階フィルタリング

最初の3段階のフィルタリングを通過した後、EAはそのイベントが設定された時間ウィンドウ内に入っているかどうかを確認します。この処理は、EAの実行中におこなわれます。

レベル4:時間ウィンドウ

最終段階は関連性の判定です。1か月後に発表されるニュースは現時点では必要ありません。また、昨日発表されたニュースはすでに市場に織り込まれている可能性があります。そのため、イベントは、TimeCurrent()が「ニュース発表前の指定時間」と「ニュース発表後の指定時間」の範囲内にある場合にアクティブとみなされます。一般的には、発表の15~30分前にポジションを決済し、発表後60分にボラティリティおよび価格変動の方向性を分析するような設定が使用されます。


MQL5バイナリリソース:効率的なキャッシュのためにイベントをオフラインテストに移行する

ニュースベースのアルゴリズム取引をテストする際の問題の一つは、ストラテジーテスターがインターネットへアクセスできないことです。この制約により、テスト速度が向上し、非決定的な要因の影響を排除できますが、一方でニュースベースの戦略をテストすることが難しくなります。

EAがテスター内でCalendarValueHistory()関数を呼び出すと、エラーが返され、結果配列は空になります。そのため、戦略をテストするには、過去のニュースデータを.ex5実行ファイル内に埋め込む必要があります。そこで利用するのがMQL5バイナリリソースです。なぜこの方法を選ぶのでしょうか。それは、構造化データへアクセスする最も高速な方法だからです。アクセス速度は実質的にコンピュータのファイルシステム性能によってのみ制限されます。

ここでは、MqlCalendarValue []配列をコンパクトなバイナリファイルへ変換し、それをコードへ埋め込む方法を見ていきます。これにより、テスターはRAM上のデータへ極めて高速にアクセスできるようになります。最初のステップとして、現在の経済指標カレンダーデータをダウンロードし、バイナリファイルとして保存するエクスポート用スクリプトを作成します。

実践例:イベントをバイナリファイルへエクスポートするスクリプト

スクリプトの完全なコードは、記事に添付されているExportCalendarForTester.mq5ファイルに含まれています。


ステップ1:配列の収集とフィルタリング

リソース内には世界中のすべてのイベントを保存するわけではありません。バイナリファイルへエクスポートする段階で、EAと同じく、通貨、重要度、イベントタイプのフィルタを適用します。スクリプトの入力パラメータでは、対象通貨リスト、イベント取得期間、イベントコード、最低重要度のリストを指定します。

InpEventCodesパラメータに指定するイベントコード一覧は、デフォルトでは空になっています。この場合、すべてのイベントタイプが読み込まれます。フィルタを絞り込むことも可能です。たとえば、米国雇用統計(Non-Farm Payrolls)のみを対象とする場合は、NONFARMを指定します。

InpUseCommonDirフラグは、バイナリファイルの保存先を指定します。trueを設定すると、バイナリファイルはすべてのクライアントターミナルで共有される\Terminal\Common\Filesフォルダに保存されます。

//--- input parameters
input string                          InpCurrencies     = "USD";
input datetime                        InpDateFrom       = D'2025.01.01';
input datetime                        InpDateTo         = 0;
input string                          InpEventCodes     = "";
input ENUM_CALENDAR_EVENT_IMPORTANCE  InpMinImportance  = CALENDAR_IMPORTANCE_HIGH;
input string                          InpOutputFile     = "calendar_test_res.bin";
input bool                            InpUseCommonDir   = true;

入力パラメータで指定された値を用いてイベントを読み込み、フィルタリングするスクリプトの該当部分は以下のとおりです。

  Print("🔄 Calendar export:");
  Print("----------------------------------");
  Print("Filtering options:");
  Print(" 🟨 Interval = ", InpDateFrom, " — ", InpDateTo);
  Print(" 🟨 Currencies = ", InpCurrencies, "\n 🟨 Event Codes = ", InpEventCodes, "\n 🟨 Min Importance = ", EnumToString(InpMinImportance));
  Print("----------------------------------");

//--- initialize filter by currencies
  ArrayResize(currencies, 0);
  if(InpCurrencies == "")
    return;
  StringSplit(InpCurrencies, ',', currencies);
  currencies_size = ArraySize(currencies);
  for(int i = 0; i < currencies_size; i++)
    StringToUpper(currencies[i]);

//--- initialize the filter by event codes
  ArrayResize(event_codes, 0);
  if(InpEventCodes != "")
    StringSplit(InpEventCodes, ',', event_codes);
  event_codes_Size = ArraySize(event_codes);

//--- load calendar values with the CURRENCY FILTER (if specified)
  if(currencies_size > 0)
   {
    ArrayResize(values_size, currencies_size);
    ArrayFill(values_size, 0, currencies_size, 0);

    for(int i = 0; i < currencies_size; i++)
     {
      if(LoadCalendar(raw_values, InpDateFrom, InpDateTo, "", currencies[i]))
       {
        raw_values_size = ArraySize(raw_values);
        //--- load events with an IMPORTANCE AND EVENT CODE FILTER
        for(int k = 0; k < raw_values_size; k++)
         {
          //--- get event description
          if(CalendarEventById(raw_values[k].event_id, event))
           {
            //--- take indicators only
            if(event.type != CALENDAR_TYPE_INDICATOR)
              continue;                                   // nothing else to filter

            //--- check by IMPORTANCE
            if(event.importance < InpMinImportance)
              continue;                                   // nothing else to filter

            //--- check by EVENT CODE (if specified)
            if(event_codes_Size > 0)
             {
              bool code_allowed = false;
              for(int c = 0; c < event_codes_Size; c++)
               {
                StringToUpper(event.event_code);
                if(StringFind(event.event_code, event_codes[c]) >= 0)
                 {
                  code_allowed = true;
                  break;
                 }
               }
              if(code_allowed == false)
                continue;
             }

            //--- replenish the array of filtered events
            int event_index = ArraySize(values);
            ArrayResize(values, event_index + 1);
            values[event_index] = raw_values[k];
            values_size[i]++;
           }
         }
        Print("✅ Received values BY CURRENCY \"", currencies[i], "\": ", raw_values_size, " → Of these, filtered: ", values_size[i]);
       }
      else
       {
        int error = GetLastError();
        if(error == 0)
          Print("⚠ LoadCalendar Info: No Events for ", currencies[i]);
        else
          Print("❌ LoadCalendar Error: ", error, " for ", currencies[i]);
        return;                                     // nothing else to filter
       }
     }
   }

提供コードの説明:

  • values_size []配列は、入力で指定された各通貨コードごとにフィルタリングされたイベント数を格納します。
  • MQL5のdatetime型におけるゼロ値は、1970.01.01 00:00:00を表します。
  • さらにイベントタイプによる追加フィルタリングがおこなわれます。ENUM_CALENDAR_EVENT_TYPE::CALENDAR_TYPE_INDICATOR型のイベントのみが処理対象となります。これらは経済指標の発表に該当するものであり、スピーチなどの定性的なニュースではありません。それ以外のニュースはすべて除外されます。この処理はフィルタリングの最初の段階におけるバリデーションでおこなわれます。
//--- take only indicators
if(event.type != CALENDAR_TYPE_INDICATOR)
  continue;                                   // Nothing else to filter


それでは、異なるフィルタリングパラメータの組み合わせでスクリプトを実行し、イベントの読み込みおよびフィルタリング処理がどの程度高速に動作するかを確認します。処理速度はコンピュータの性能や、インターネット経由でデータサーバーへ接続する速度に依存することは明らかです。それにもかかわらず、ストレステストを実施します。結果は以下の通りです。

利用可能なすべての履歴にわたる、高重要度のUSDイベント全件

13:59:43.724    🔄 Calendar export:
13:59:43.724    ----------------------------------
13:59:43.724    Filtering options:
13:59:43.724      🟨 Interval = 1970.01.01 00:00:00 — 1970.01.01 00:00:00
13:59:43.724      🟨 Currencies = USD
13:59:43.724      🟨 Event Codes = 
13:59:43.724      🟨 Min Importance = CALENDAR_IMPORTANCE_HIGH
13:59:43.724    ----------------------------------
13:59:45.511    ✅ Received values BY CURRENCY "USD":53346 → Of these, filtered:9009
13:59:45.511    ----------------------------------
13:59:45.513    ✅ Saved:USD_calendar_test_res.bin   Size:1153152 bytes  (9009 events)

フィルタリングされた値配列(MqlCalendarValue構造体)の取得時間は1.80 秒(1フィルタあたり0.20ms)でした。


利用可能なすべての履歴にわたる、高重要度のUSD、EUR、JPYイベント全件

14:03:08.724    🔄 Calendar export:
14:03:08.724    ----------------------------------
14:03:08.724    Filtering options:
14:03:08.724      🟨 Interval = 1970.01.01 00:00:00 — 1970.01.01 00:00:00
14:03:08.724      🟨 Currencies = USD,EUR,JPY
14:03:08.724      🟨 Event Codes = 
14:03:08.724      🟨 Min Importance = CALENDAR_IMPORTANCE_HIGH
14:03:08.724    ----------------------------------
14:03:10.488    ✅ Received values BY CURRENCY "USD":53346 → Of these, filtered:9009
14:03:10.947    ✅ Received values BY CURRENCY "EUR":45139 → Of these, filtered:1102
14:03:11.404    ✅ Received values BY CURRENCY "JPY":18907 → Of these, filtered:937
14:03:11.404    ----------------------------------
14:03:11.406    ✅ Saved:USD_calendar_test_res.bin   Size:1153152 bytes  (9009 events)
14:03:11.407    ✅ Saved:EUR_calendar_test_res.bin   Size:141056 bytes  (1102 events)
14:03:11.408    ✅ Saved:JPY_calendar_test_res.bin   Size:119936 bytes  (937 events)

フィルタリングされた値配列(MqlCalendarValue構造体)の取得時間は2.68秒(1フィルタあたり0.24ms)でした。


USDにおける高重要度のNFPイベント(「非農業部門雇用者数」)について、利用可能なすべての履歴にわたり抽出した結果は以下のとおりです。

14:07:22.203    🔄 Calendar export:
14:07:22.203    ----------------------------------
14:07:22.203    Filtering options:
14:07:22.203      🟨 Interval = 1970.01.01 00:00:00 — 1970.01.01 00:00:00
14:07:22.203      🟨 Currencies = USD
14:07:22.203      🟨 Event Codes = NONFARM
14:07:22.203      🟨 Min Importance = CALENDAR_IMPORTANCE_HIGH
14:07:22.203    ----------------------------------
14:07:22.290    ✅ Received values BY CURRENCY "USD":53346 → Of these, filtered:473
14:07:22.290    ----------------------------------
14:07:22.291    ✅ Saved:USD_calendar_test_res.bin   Size:60544 bytes  (473 events)

フィルタリングされた値配列(MqlCalendarValue構造体)の取得時間は0.09秒(1フィルタあたり0.18ms)でした。

備考:

  1. フィルタにおいてイベントコード全体を指定する必要はありません。コード文字列の中に含まれる一意な部分を指定するだけで十分です。たとえば「非農業部門雇用者数(non-farms)」の場合、完全なコードは「NONFARM-PAYROLLS」ですが、「NONFARM」と指定するだけで条件として成立します。
  2. MetaTrader 5ターミナル上でリアルタイムトレードシステムを実行する場合、全期間にわたるすべてのイベントをダウンロードする必要はほとんどありません。通常は当日および翌週程度の直近イベントのみを取得します。そのため、ニュースEAアルゴリズムにおける読み込み時間は実質的に無視できるレベルになります。


ステップ2:イベント配列をバイナリファイルにエクスポートする

SaveToBinary関数は、フィルタリングされたイベントをバイナリファイルに保存します。生成されるファイル数は入力で指定された通貨コードの数と同じになり、各通貨ごとに個別のバイナリファイルへエクスポートされます。ファイル名は通貨コードの接頭辞から始まり、たとえば「USD_calendar_test_res.bin」のようになります。このようにして、通貨コードとそのイベントリストとの間に1対1の対応関係が得られます。

//+------------------------------------------------------------------+
//| Save an array to a binary file                                   |
//+------------------------------------------------------------------+
void SaveToBinary(MqlCalendarValue &values[], const int &vls_size[], const string filename, const string &currencies[])
 {
  if(ArraySize(values) == 0)
   {
    Print("⚠️ Nothing to save");
    return;
   }

  Print("----------------------------------");
  int offset = 0;
  for(int i = 0; i < ArraySize(vls_size); i++)
   {
    int file_handle = FileOpen(currencies[i] + "_" + filename, FILE_WRITE | FILE_BIN | (InpUseCommonDir ? FILE_COMMON : 0));

    if(file_handle == INVALID_HANDLE)
     {
      Print("❌ FileSave failed: ", GetLastError());
      return;
     }

    FileWriteArray(file_handle, values, offset, vls_size[i]);
    FileFlush(file_handle);
    FileClose(file_handle);

    Print("✅ Saved: ", currencies[i] + "_" + filename, "   Size: ", vls_size[i] * sizeof(MqlCalendarValue), " bytes", "  (", vls_size[i], " events)");

    offset += vls_size[i];
   }
 }

イナリファイルへイベントのエクスポートスクリプトを正常に実行すると、MetaTrader 5の[エキスパート]タブには次のようなメッセージが表示されます。

14:28:42.077    ----------------------------------
14:28:42.078    ✅ Saved:USD_calendar_test_res.bin   Size:58240 bytes  (455 events)
14:28:42.079    ✅ Saved:EUR_calendar_test_res.bin   Size:7680 bytes  (60 events)


ステップ3:リソースをEAにコンパイルする

MQL5/Files/にExportCalendarForTester.mq5スクリプトを実行した後、USD_calendar_test_res.binおよびEUR_calendar_test_res.binといったファイルが生成されます。次に、これらのファイルをEAに「埋め込み」ます。EAファイルの先頭(#propertyディレクティブの後)に、使用する通貨が1つの場合は1行、複数通貨の場合は複数行、以下の形式を追加します。

// Embed the binary file as a static resource at the compilation stage
#resource "\\Files\\USD_calendar_test_res.bin" as MqlCalendarValue USD_res_calendar_data[]
#resource "\\Files\\EUR_calendar_test_res.bin" as MqlCalendarValue EUR_res_calendar_data[]

注記:

  1. #resourceのパスはMQL5/Files/フォルダを基準として指定されます。\\Files\\接頭辞は必須です。
  2. EAをコンパイルすると、MetaEditorの[エラー]タブには次のようなメッセージが表示されます。
  • 'USD_calendar_test_res.bin' as 'const MqlCalendarValue USD_res_calendar_data[455]' 
  • 'EUR_calendar_test_res.bin' as 'const MqlCalendarValue EUR_res_calendar_data[60]' 

EA起動時には、エクスポート段階で保存されたイベント構造体が、それぞれUSD_res_calendar_data[]およびEUR_res_calendar_data配列に格納されます。


EAへの統合:自動モード切り替え

目的は、同一のEAコードをリアルタイム環境とストラテジーテスターの両方で動作させ、データソースを自動的に選択できるようにすることです。MQLInfoInteger (MQL_TESTER) 関数は、EAがストラテジーテスターまたは最適化環境で動作している場合にtrueを返します。

//+------------------------------------------------------------------+
//| Initialization: select a data source                             |
//+------------------------------------------------------------------+
int OnInit()
 {
  Print("🔄 Initializing the news module:");

//--- initialize filter by currencies
  ArrayResize(currencies, 0);
  if(InpCurrencies == "")
    return INIT_FAILED;
  StringSplit(InpCurrencies, ',', currencies);
  currencies_size = ArraySize(currencies);
  for(int i = 0; i < currencies_size; i++)
    StringToUpper(currencies[i]);

//--- initialize the filter by event codes
  ArrayResize(event_codes, 0);
  if(InpEventCodes != "")
    StringSplit(InpEventCodes, ',', event_codes);
  event_codes_Size = ArraySize(event_codes);

//--- define the execution environment
  bool is_tester = MQLInfoInteger(MQL_TESTER) || MQLInfoInteger(MQL_OPTIMIZATION) || MQLInfoInteger(MQL_VISUAL_MODE);
  if(is_tester)
   {
    //--- TESTER MODE: Load from resource
    if(!LoadFromResource())
     {
      Print("❌ ERROR: Failed to load calendar from resource");
      return INIT_FAILED;
     }
    is_live_mode = false;
    Print("⚠️ Mode: TESTER (data from resource)");
   }
  else
   {
    //--- LIVE MODE: Load from API
    if(!LoadFromCalendarAPI())
     {
      int error = GetLastError();
      Print("❌ ERROR: Failed to load calendar from API - ", error);
      return INIT_FAILED;
     }
    is_live_mode = true;

    Print("⚠️ Mode: LIVE (data from API)");
   }

  return INIT_SUCCEEDED;
 }


提供コードの説明:

主なチェックは、OnInit () EA初期化イベントハンドラでおこなわれます。

   //--- define the execution environment
   bool is_tester = MQLInfoInteger(MQL_TESTER) || MQLInfoInteger(MQL_OPTIMIZATION) || MQLInfoInteger(MQL_VISUAL_MODE);
   if(is_tester)
    {
      //--- TESTER MODE: Load from resource
      if(!LoadFromResource())
       {
        ...
       }
    }
   else
    {
      //--- LIVE MODE: Load from API
      if(!LoadFromCalendarAPI())
       {
        ...
       }
    }

提供コードの説明:

実行中のMQL5プログラム(ここではEA)がどのモードで動作しているかを判定します。ここで注目するフラグは以下のとおりです。

  • MQL_TESTER:ストラテジーテスター上でプログラムが実行されていることを示すフラグ
  • MQL_OPTIMIZATION:最適化処理中にプログラムが実行されていることを示すフラグ
  • MQL_VISUAL_MODE:ビジュアルテストモードでプログラムが実行されていることを示すフラグ
れらのいずれかのフラグが有効になっている場合は、リソースからイベントリストを読み込みます。一方、それ以外の場合は、通常どおりカレンダーAPIを通じてサーバーからイベントリストを取得します。


14:42:18.894    🔄 Initializing news module:
14:42:18.905    ✅ Events from Server Loaded:455 events for:USD
14:42:18.914    ✅ Events from Server Loaded:60 events for:EUR
14:42:18.914    ⚠️ Mode:LIVE (data from API)



データ変換チェーンの検証:イベント → バイナリファイル → リソースにコンパイル → リソースからイベントを取得

残る作業は、ストラテジーテスター環境においてイベントが正しく取得されていることを確認し、リアルタイムで取得されるリストと完全に一致することを検証することです。これにより、ニューストレードアルゴリズムの自動テストおよび最適化が可能であることが確認できます。

そのために、サーバーから取得したイベントおよびリソースから読み込んだイベントの内容を、ターミナル/ストラテジーテスターのログへ出力するようにします。完全なImportTesterLog.txtファイル(テスター実行結果を含む)が添付されています。以下はそのログの一部であり、各通貨コードごとのイベント配列の先頭と末尾を示しています。

ストラテジーテスターのビジュアルモードでの単一実行結果

16:48:22.527    EURUSD,M5: testing of Experts\ImportCalendarValidation-EA.ex5 from 2026.01.01 00:00 to 2026.03.07 00:00 started with inputs:
16:48:22.527      InpCurrencies=USD,EUR
16:48:22.527      InpDateFrom=1735689600
16:48:22.527      InpDateTo=1767225600
16:48:22.527      InpEventCodes=
16:48:22.527      InpMinImportance=3
16:48:22.546   🔄 Initializing news module:
16:48:22.546   ✅ Events from Resource Loaded:455 events for:USD
16:48:22.546   ✅ Event #0
16:48:22.546   ID:                    230215
16:48:22.546   Event ID:          840140001
16:48:22.546   Time:               2025.01.02 16:30:00
16:48:22.546   Impact:            CALENDAR_IMPACT_POSITIVE
16:48:22.546   Revision:          0
16:48:22.546   Actual:             211.0
16:48:22.546   Revised:           220.0
16:48:22.546   Forecast:          219.0
16:48:22.546   Previous:          219.0
16:48:22.546   ✅ Event #1
16:48:22.546   ID:                   230641
16:48:22.546   Event ID:          840500001
16:48:22.546   Time:               2025.01.02 17:45:00
16:48:22.546   Impact:            CALENDAR_IMPACT_NEGATIVE
16:48:22.546   Revision:         3
16:48:22.546   Actual:             49.4
16:48:22.546   Forecast:          50.5
16:48:22.546   Previous:          49.7
 ...
16:48:22.553   ✅ Event #453
16:48:22.553   ID:                   274419
16:48:22.553   Event ID:          840510001
16:48:22.553   Time:               2025.12.30 17:45:00
16:48:22.553   Impact:            CALENDAR_IMPACT_POSITIVE
16:48:22.553   Revision:          0
16:48:22.553   Actual:             43.5
16:48:22.553   Forecast:          42.4
16:48:22.553   Previous:          36.3
16:48:22.553   ✅ Event #454
16:48:22.553   ID:                   274484
16:48:22.553   Event ID:          840140001
16:48:22.553   Time:               2025.12.31 16:30:00
16:48:22.553   Impact:            CALENDAR_IMPACT_POSITIVE
16:48:22.553   Revision:          0
16:48:22.553   Actual:             199.0
16:48:22.553   Revised:           215.0
16:48:22.553   Forecast:          227.0
16:48:22.553   Previous:          214.0
...
16:48:22.553   ✅ Events from Resource Loaded:60 events for:EUR
16:48:22.553   ✅ Event #0
16:48:22.553   ID:                   231322
16:48:22.553   Event ID:         999030013
16:48:22.553   Time:              2025.01.07 13:00:00
16:48:22.553   Impact:           CALENDAR_IMPACT_NA
16:48:22.553   Revision:         1
16:48:22.553   Actual:            2.4
16:48:22.553   Forecast:        2.4
16:48:22.553   Previous:         2.2
16:48:22.553   ✅ Event #1
16:48:22.553   ID:                  187384
16:48:22.553   Event ID:         999040007
16:48:22.553   Time:              2025.01.08 13:00:00
16:48:22.553   Impact:          CALENDAR_IMPACT_POSITIVE
16:48:22.553   Revision:         0
16:48:22.553   Actual:            21.0
16:48:22.553   Revised:          17.8
16:48:22.553   Forecast:         15.7
16:48:22.553   Previous:         17.7
...
16:48:22.555   ✅ Event #58
16:48:22.555   ID:                  204746
16:48:22.555   Event ID:         999010006
16:48:22.555   Time:             2025.12.18 16:15:00
16:48:22.555   Impact:          CALENDAR_IMPACT_NA
16:48:22.555   Revision:         0
16:48:22.555   Actual:            2.0
16:48:22.555   Previous:         2.0
16:48:22.555   ✅ Event #59
16:48:22.555   ID:                  204762
16:48:22.555   Event ID:         999010007
16:48:22.555   Time:             2025.12.18 16:15:00
16:48:22.555   Impact:          CALENDAR_IMPACT_NA
16:48:22.555   Revision:         0
16:48:22.555   Actual:            2.15
16:48:22.555   Previous:         2.15
16:48:22.555   ⚠️ Mode:TESTER (data from resource)

リソースから読み込まれたイベント配列は約10msで完全にロードされることが確認できます。これは予想通りの結果です。リソースはEAのコードに組み込まれており、テスト開始時に同時に読み込まれるためです。

同じEAの実行(起動)をMetaTrader 5ターミナルのライブモードでおこなった場合にも、同様にイベント一覧を含むログファイルが生成されます。完全なLoadLiveLog.txtにはライブ取得結果が記録されています。以下はそのログの一部であり、各通貨コードごとのイベント配列の先頭と末尾を示しています。

サーバーからのライブイベント取得結果

17:27:25.250    🔄 Initializing news module:
17:27:25.258    ✅ Received values BY CURRENCY "USD":3589 → Of these, filtered:455
17:27:25.258    ✅ Events from Server Loaded:455 events for:USD
17:27:25.258    ✅ Event #0
17:27:25.258    ID:                   230215
17:27:25.258    Event ID:          840140001
17:27:25.258    Time:               2025.01.02 16:30:00
17:27:25.258    Impact:            CALENDAR_IMPACT_POSITIVE
17:27:25.258    Revision:          0
17:27:25.258    Actual:             211.0
17:27:25.258    Revised:           220.0
17:27:25.258    Forecast:          219.0
17:27:25.258    Previous:          219.0
17:27:25.258    ✅ Event #1
17:27:25.258    ID:                   230641
17:27:25.258    Event ID:          840500001
17:27:25.258    Time:               2025.01.02 17:45:00
17:27:25.258    Impact:            CALENDAR_IMPACT_NEGATIVE
17:27:25.258    Revision:          3
17:27:25.258    Actual:             49.4
17:27:25.258    Forecast:        50.5
17:27:25.258    Previous:          49.7
...
17:27:25.288    ✅ Event #453
17:27:25.288    ID:                   274419
17:27:25.288    Event ID:          840510001
17:27:25.288    Time:               2025.12.30 17:45:00
17:27:25.288    Impact:            CALENDAR_IMPACT_POSITIVE
17:27:25.288    Revision:          0
17:27:25.288    Actual:             43.5
17:27:25.288    Forecast:          42.4
17:27:25.288    Previous:          36.3
17:27:25.288    ✅ Event #454
17:27:25.288    ID:                    274484
17:27:25.288    Event ID:          840140001
17:27:25.288    Time:               2025.12.31 16:30:00
17:27:25.288    Impact:            CALENDAR_IMPACT_POSITIVE
17:27:25.288    Revision:          0
17:27:25.288    Actual:             199.0
17:27:25.288    Revised:           215.0
17:27:25.288    Forecast:         227.0
17:27:25.288    Previous:          214.0

17:27:25.301    ✅ Received values BY CURRENCY "EUR":3116 → Of these, filtered:0
17:27:25.301    ✅ Events from Server Loaded:60 events for:EUR
17:27:25.301    ✅ Event #0
17:27:25.301    ID:                   231322
17:27:25.301    Event ID:          999030013
17:27:25.301    Time:               2025.01.07 13:00:00
17:27:25.301    Impact:            CALENDAR_IMPACT_NA
17:27:25.301    Revision:          1
17:27:25.301    Actual:             2.4
17:27:25.301    Forecast:          2.4
17:27:25.301    Previous:          2.2
17:27:25.301    ✅ Event #1
17:27:25.301    ID:                   187384
17:27:25.301    Event ID:          999040007
17:27:25.301    Time:               2025.01.08 13:00:00
17:27:25.301    Impact:            CALENDAR_IMPACT_POSITIVE
17:27:25.301    Revision:          0
17:27:25.301    Actual:             21.0
17:27:25.301    Revised:           17.8
17:27:25.301    Forecast:         15.7
17:27:25.301    Previous:          17.7
...
17:27:25.303    ✅ Event #58
17:27:25.303    ID:                   204746
17:27:25.303    Event ID:          999010006
17:27:25.303    Time:               2025.12.18 16:15:00
17:27:25.303    Impact:            CALENDAR_IMPACT_NA
17:27:25.303    Revision:          0
17:27:25.303    Actual:             2.0
17:27:25.303    Previous:          2.0
17:27:25.303    ✅ Event #59
17:27:25.303    ID:                   204762
17:27:25.303    Event ID:          999010007
17:27:25.303    Time:               2025.12.18 16:15:00
17:27:25.303    Impact:            CALENDAR_IMPACT_NA
17:27:25.303    Revision:          0
17:27:25.303    Actual:           2.15
17:27:25.303    Previous:         2.15
17:27:25.303    ⚠️ Mode:LIVE (data from API)

フィルタリングとログ出力を含むフルダウンロード処理は約50msで完了します。それでも依然として十分に高速であり、イベントのダウンロードおよびフィルタリング時間は無視できるレベルです。両方のログファイルを比較すると、イベント数および各フィールドの値の両方が完全に一致していることが確認できます。これにより、データ変換チェーンの検証は正常に完了しました。

典型的な間違いと誤った期待の分析

MQL5の経済指標カレンダー統合において、開発者がよく犯す6つの典型的なミスを見ていきます。これらはすべて実運用で検証されており、場合によっては資金損失につながる可能性があります。

1. 「カレンダーは価格変動を予測する

誤った期待:

高重要度のニュースが発表され、実績値が予想値から大きく乖離した場合、価格は必ずその乖離方向に動く。たとえば「実績 > 予想」であれば単純に買うべきだ、という考え方です。

現実:

経済指標カレンダーは売買シグナル生成器ではなく、データソースにすぎません。カレンダーは「何が起きたか」を示すだけであり、「市場がどう反応するか」を示すものではありません。「直感的に正しい」と思われる反応と異なる動きが発生する理由は以下の通りです。

  • 市場は発表数日前から期待値を織り込み済みであり、発表時点では「材料出尽くし」が発生することがある
  • インフレ指標は、金融政策が引き締め局面か緩和局面かによって、同じ結果でも通貨高・通貨安のどちらにも作用し得る
  • 良好な指標であっても、前回値が下方修正された場合、全体としてはネガティブに解釈されることがある
  • 複数通貨・複数指標が同時に発表されることでクロス影響が発生し、単純な一方向解釈が不可能になる

したがって、正しいアプローチはエントリーシグナルとしてではなく、ボラティリティフィルタとしてカレンダーを利用することです。

//--- instead of
if(actual > forecast)
 OrderSend(...);

//--- use:
if(IsHighImpactNewsComingSoon(30)) 
 {
   //--- reduce the position size or temporarily suspend trading
   ReduceRiskExposure();
 }
黄金律:カレンダーが答えるのは「いつボラティリティの上昇が起こるか」であり、「どちら方向にトレードすべきか」ではありません。


2. 「すべてのHIGHイベントは同じ重要度である

誤った期待:

CALENDAR_IMPORTANCE_HIGHは、すべてのイベントが市場を50pips以上動かすことを保証する指標であり、すべての高重要度ニュースを同一アルゴリズムで取引できる、という考え方です。

現実:

ENUM_CALENDAR_EVENT_IMPORTANCEにおける重要度の値は、あくまでカレンダー編集者による定性的な評価であり、実際の市場インパクトを定量的に保証するものではありません。たとえば、どちらもHIGHと分類されるイベントであっても、市場への影響度は大きく異なります。

一つ目の例として、米国の非農業部門雇用者数は、雇用状況を示す重要指標であり、FRBの政策判断にも直接影響するため、80〜150ポイント程度の大きなボラティリティ反応を示します。一方で、ユーロ圏の製造業PMIは、特定セクターに限定された指標であり、ECB政策への影響も相対的に小さいため、10〜30ポイント程度の反応にとどまることが多いです。

したがって、正しいアプローチは重要度フィルタだけに依存するのではなく、イベントコードの優先リストを併用することです。

//--- a list of events that are really worth reacting to
bool IsGoodEvent(const string event_code)
 {
   static const string tier1_codes[] = 
   {
      "NONFARM", "CPI", "GDP", "RATE", "FOMC", "ECB_RATE", 
      "RETAIL_SALES", "UNEMPLOYMENT", "PMI_MANUFACTURING"
   };
   
   for(int i = 0; i < ArraySize(tier1_codes); i++)
      if(StringFind(event_code, tier1_codes[i]) != -1)
         return true;
   return false;
 }

//--- use in filter
if(event.importance == CALENDAR_IMPORTANCE_HIGH && IsGoodEvent(event.event_code))
 {
   //--- handle only truly significant news
 }

推奨事項:

過去のボラティリティ分析に基づいて独自のイベントランキングを作成することが最も信頼性が高く、プリセットのラベルよりも実用的です。


3. TimeLocal() を TimeTradeServer() の代わりに使用する

誤った期待:

MqlCalendarValue::time 構造体内に格納されるイベント時刻はローカルタイム(またはUTC)であり、そのためTimeLocal()やTimeGMT()と比較すればよい、という考え方です。

現実:

経済指標カレンダーのすべての時間データは、取引サーバーの時間帯 (TimeTradeServer())に基づいて返されます。これは設計上の仕様であり、追加の手動変換を不要にする一方で、開発者側には一貫した時間管理を要求します。

この誤りの影響は重大です。たとえばサーバーがEET (UTC+2)で動作しているのに対し、開発環境でTimeLocal()(たとえばMSK、UTC+3)を使用した場合、常に1時間のズレが発生します。その結果、EAはニュースを見逃したり、逆に発表後に反応してしまう可能性があります。

したがって、正しいアプローチはすべての時間比較においてTimeTradeServer()を使用することです。

//--- WRONG — risk of desynchronization
datetime now = TimeLocal();
if(event.time - now < 1800)
 { ... }

//--- RIGHT — guaranteed synchronization
datetime now = TimeTradeServer();
if(event.time - now < 1800)
 { ... }

//--- in the tester, TimeTradeServer() returns the model time, so the logic works identically to live

推奨事項:

デバッグログにTimeToString(TimeTradeServer(), TIME_MINUTES)の出力を追加し、イベント時刻と比較してください。追加の変換なしで一致するはずです。


4. 「イベントフィールドが空になる可能性を忘れる

誤った期待:

actual_valueやforecast_valueなどの数値フィールドには常に正しい数値が格納されており、それらをそのまま使用したり、単純に1,000,000で割れば安全に比較できるという考え方です。

現実:

ドキュメントによると、MqlCalendarValue構造体の数値フィールドは実際の値が1,000,000倍された形で格納されているか、値が存在しない場合はLONG_MINが格納されます。このチェックを無視した場合に起こる問題は以下のとおりです。

//--- error
double actual = values[i].actual_value / 1000000.0; // if actual_value == LONG_MIN, result: -9223372036.854776

if(actual > forecast) // comparison with a "garbage" number causes a false alarm
  OpenBuy();

正しいアプローチは、MqlCalendarValue構造体に用意されている組み込みメソッドを使用して、値を安全に取得することです。

//--- the right approach is built-in methods
if(values[i].HasActualValue() && values[i].HasForecastValue())
 {
  double actual = values[i].GetActualValue();
  double forecast = values[i].GetForecastValue();

  if(!MathIsNaN(actual) && !MathIsNaN(forecast))
   {
    double deviation = actual - forecast;
    // ... analysis logic
   }
 }
//+------------------------------------------------------------------+

注記:

GetActualValue()、GetForecastValue()などの関数は、データが存在しない場合にはNaNを返します。そのため、計算に使用する前に必ずMathIsValidNumber()またはMathIsNaN()によって結果をチェックする必要があります。


5. 「OnTick()内でCalendar API関数を呼び出す

誤った期待:

最新データを常に取得するために、毎ティックCalendarValueHistory()を呼び出せば、重要なニュースを見逃さないという考え方です。

現実:

カレンダーAPIはリモートサーバーと通信する仕組みであり、MetaTrader 5には厳格なリクエスト制限が存在します。そのため、OnTick()(1秒間に数十回発火する可能性がある)内で呼び出すと、以下の問題が発生します。

  • エラー5204(ERR_CALENDAR_TOO_MANY_REQUESTS)により、一時的にカレンダーアクセスがブロックされる
  • ネットワークリクエストが取引ループに混入し、実行遅延やスリッページ増加を引き起こす
  • 同じデータを繰り返し取得することで不要な通信負荷が発生する
したがって正しい設計は、キャッシュ機構とインクリメンタル更新を組み合わせて運用することです。
//--- global variables
MqlCalendarValue calendar_cache[];
bool cache_initialized = false;
long last_change_id = 0;

//+------------------------------------------------------------------+
int OnInit()
 {
//--- initial history loading (once at startup)
  datetime from = TimeCurrent() - 7 * 86400;
  datetime to = TimeCurrent() + 30 * 86400;

  if(CalendarValueHistory(calendar_cache, from, to, "USD"))
   {
    cache_initialized = true;
   }

//--- set a timer for periodic updates (no more than 5-10 minutes)
  EventSetTimer(300);
  return INIT_SUCCEEDED;
 }
//+------------------------------------------------------------------+
void OnTimer()
 {
  if(!cache_initialized)
    return;

  MqlCalendarValue updates[];

//--- only request changes since the last update
  if(CalendarValueLast(last_change_id, updates, "USD") > 0)
   {
    if(ArraySize(updates) > 0)
     {
      //--- merge new data with the cache
      MergeUpdates(calendar_cache, updates);
      last_change_id = updates[ArraySize(updates) - 1].change_id;
     }
   }
 }
//+------------------------------------------------------------------+
void OnTick()
 {
//--- work only with local cache - no network delays
  if(cache_initialized)
    ProcessNewsSignals(calendar_cache);
 }

推奨事項:

OnTick ()はローカルデータの処理のみに使用すべきです。ネットワークリクエストはOnInitOnTimer、またはユーザーイベント経由でのみ実行するのが適切です。


6. 「新しいイベントでテストする際にEAの再コンパイルを忘れる

誤った期待:

Filesフォルダ内のcalendar_test_res.binリソースファイルを更新すれば、ストラテジーテスターは自動的に新しいイベントを認識し、EAの再コンパイルは不要であるという考え方です。

現実:

#resourceディレクティブは、データをコンパイル時に.ex5実行ファイルへ埋め込みます。そのため、外部の.binファイルを変更しても動的には反映されず、EAはビルド時に埋め込まれた古いリソースを引き続き使用します。

エラーの症状:

  • ストラテジーテスターのログに、リソース更新後に追加されたイベントが表示されない
  • 重要なニュースがファイルには存在するにもかかわらず、EAが認識しない
  • コード上は正しいにもかかわらず、テスト結果が期待と一致しない

したがって正しい対応は、リソースを更新した後は必ずEAを再コンパイルすることです。

//--- at the beginning of the EA file
#resource "\\Files\\USD_calendar_test_res.bin" as MqlCalendarValue USD_res_calendar_data[]

//--- after USD_calendar_test_res.bin update:
// 1. Save changes to the resource file.
// 2. Press F7 in MetaEditor (or Compile in the menu).
// 3. Make sure there are no errors in the compilation log.
// 4. Run the test again.

推奨事項:

コンパイルログには、リソースのバージョン情報(たとえばハッシュ値や最終更新日時)を出力し、.ex5内で使用されているデータの鮮度を視覚的に確認できるようにすることが推奨されます。

備考:

本セクションで取り上げたエラーは、MQL5の構文理解不足によって発生しているのではなく、経済データ(指標)の本質に対する単純化された理解に起因しています。ここで説明した6つの誤りを回避できるようになれば、単に動作するコードではなく、市場変化や経済当局の要件にも適応可能な安定したトレードシステムを構築できるようになります。この視点こそが、アルゴリズム取引におけるアマチュアとプロフェッショナルの違いを決定づけます。


結論

MetaTrader 5ターミナルの経済指標カレンダーは非常に強力なツールですが、他のツールと同様に、その利用には文脈理解・運用上の規律・プラットフォーム制約の考慮が不可欠です。

本記事では、EAにおけるニュースAPIの具体的な実装および利用構造について整理しました。以下の要素を組み合わせることで、手動のニューストレードを再現性のあるモジュールへと変換できます。

  • カレンダーAPIの理解(EventとValueの違い、MqlCalendarEvent / MqlCalendarValue構造体、サーバー時刻の扱い)
  • 安全なデータ取得と更新方法(初期読み込みにCalendarValueHistory、インクリメンタル更新にCalendarValueLast + change_idを使用)
  • リクエスト制限と典型的エラーの管理
  • 通貨、重要度、イベントコード、時間ウィンドウによる多段フィルタリング(ノイズ削減と重要イベント3〜5件への絞り込み)
  • フィルタ済みデータをバイナリリソースへエクスポートし、「リアルタイム ↔ ストラテジーテスター」を自動切り替えする仕組み(同一データによる一貫した動作保証)

モジュールの完成条件は、指定された期間のイベントが正常にロードされること、change_idを用いたインクリメンタル更新が制限を超えることなく正しく動作すること、そしてストラテジーテスター環境においてEAがリソースを読み込み、Live環境と同一の入力データに基づいて同一の判断を出力できることです。

推奨される次のステップ:エクスポーターの実装、.binの#resourceへの組み込み、OnInit / OnTimerによる更新ロジックの検証、そして「30分取引停止 → 60分後再開」などの制御条件を含むバックテストを実施することが推奨されます。

これにより、仮説レベルのアイデアから、検証可能でスケーラブルなニューストレードシステムへと移行できます。ニュースEAの開発は単なるプログラミングではなく、マクロ経済理論と市場実践を結ぶ実装作業です。 

以下は、MetaTrader 5カレンダーAPI関数およびニューストレードへの応用について、より深く学ぶための推奨リソースです。


記事に添付されているファイルの一覧:

ファイル名 説明
CalendarEventMonitor-EA.mq5  カレンダーデータの更新機能をテストするためのテストスクリプト
ExportCalendarForTester-S.mq5 指定されたフィルタ条件に基づいてイベントをバイナリファイルへエクスポートする処理を検証するためのテストスクリプトのコード
GetTodayEvents-S.mq5 当日分のイベント取得処理を確認するためのテストスクリプトのコード
ImportCalendarValidation-EA.mq5 ストラテジーテスター環境においてリソースからニュースを取得する動作を検証するためのテストEAのコード
ImportTesterLog.txt  ImportCalendarValidation-EA.mq5をビジュアルモードでストラテジーテスター実行した際の単一実行結果
LoadLiveLog.txt  ImportCalendarValidation-EA.mq5をLive環境で実行した際のイベント取得結果のログ

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/22196

最後のコメント | ディスカッションに移動 (8)
Stanislav Korotky
Stanislav Korotky | 1 5月 2026 において 13:32

執筆者

Если брокер учитывает переход на летнее/зимнее время — календарь автоматически подстраивается под этот переход

MQL5のAPIに何か変更があったのであれば教えてほしいのですが、以前はカレンダーはサマータイムを考慮して現在のタイムゾーンに調整されていました。つまり、夏の機能リクエストはUTC+3ゾーンのタイムスタンプを返しますが、冬の同じ履歴セクションのリクエストは、サーバーがサマータイムに切り替わるとUTC+2ゾーンのスタンプを持つイベントを取得します。したがって、6ヶ月以上のカレンダー履歴を正確にアップロードするには、ブローカーのタイムゾーン 変換履歴を分析する必要があります。詳細はコードベースにて

また、カレンダーキャッシュをリソースとしてリンクするアプローチはあまり実用的でないように思われ、特に、記事自体に記載されているエラー(EAの再コンパイルを忘れずに、など)を引き起こす。なぜ、すべてのエージェントで利用可能な Common フォルダにあるファイルとして、入力パラメータにカレンダーキャッシュを設定しないのでしょうか?

Maxim Kuznetsov
Maxim Kuznetsov | 3 5月 2026 において 17:44
もしMQL5のAPIに変更があれば教えていただきたいのですが、以前はカレンダーはサマータイムを考慮した現在のタイムゾーンに調整されていました。つまり、夏の機能リクエストでは、例えばUTC+3ゾーンのタイムスタンプが返され、冬の同じ履歴セクションのリクエストでは、サーバーがサマータイムに切り替わると、UTC+2ゾーンのラベルのイベントが返されます。したがって、6ヶ月以上のカレンダー履歴を正確にアップロードするためには、ブローカーの転送履歴を分析する必要がある。 часового пояса ブローカーを使用する必要があります。詳細はコード ベースにある。

なぜ気配値(一般的にすべてのタイムスタンプ)はUTCで保存されないのですか?

なぜディーラーのティックは、1つの同じタイムリファレンスの異なる数値表現を持っているのですか?

哲学的な質問です :-) それは間違っているし、その場で問題を引き起こすが、それが行われている方法です。


ZЫ.だから、「歴史的なニュース」は他のソースから取った方がいい。

そして、決して「時計の翻訳の歴史を分析する」必要はない。それはすべてそこにある、それはOSまたはシステムライブラリの機能である。グーグルtzdata

自転車は何台作れるか?

fxsaber
fxsaber | 3 5月 2026 において 19:30
Stanislav Korotky #:

以前は、カレンダーはサマータイムを考慮して現在のタイムゾーンに調整されていました。つまり、夏の機能リクエストでは、例えばUTC+3ゾーンのタイムスタンプが返され、冬の同じ履歴セクションへのリクエストでは、サーバーがサマータイムに切り替わったり戻ったりすると、UTC+2ゾーンのスタンプを持つイベントが返されます。

私も同じ考えです。
Stanislav Korotky
Stanislav Korotky | 4 5月 2026 において 16:09
Maxim Kuznetsov #:


ZЫ.だから、「歴史的ニュース」は他のソースから取った方がいい。

そして、決して自分で「時計の翻訳履歴を分析」してはいけない。すべてそこにある、OSやシステムライブラリの機能なのだから。グーグルtzdata

自転車は何台作れるか?


他のソースでは、この問題は解決できない。なぜなら、MT5で引用符が保存される方法に埋もれているからだ。

まずはまっすぐな自転車を見せて、それからアドバイスをしてください。

ilex044
ilex044 | 11 5月 2026 において 10:09
MetaQuotes:

現代のニューストレーダーの主な問題は、断片的なツールセットと、体系的なアルゴリズム取引のワークフローの欠如である。インターネット・ブラウザ(ニュース・サイトの閲覧)と取引端末の間で注意を分散させながら取引を行うのはかなり難しい。

ニューストレーダーのワークフローは次のようなものだ:ウェブブラウザでニュースカレンダーを素早く開き、イベントの変更をチェックする → 今後のイベントを素早く評価し、何をどのように取引するかを決定する → MetaTrader 5ターミナルに移動し、未決注文を発注するか、ターミナルに座ってニュースリリースを待ち、決定を下す。このシナリオでは、トレーダーはしばしば文脈を見失い、ニュースへの反応の遅れにつながり、ひいては損失につながる。

明確なルール、再現可能な結果、自動化されたテストなど、ニュース取引をエンジニアリングの問題のように機能させたいとお考えだろうか?この記事の目的は、MetaTrader 5用のニュースレイヤーの動作アーキテクチャを実証することです:単一のデータソース、カレンダーAPIの適切な使用、フィルタリングとキャッシュのメカニズム、テスター用のリソースへのヒストリカルイベントのエクスポート、ライブとテスターの自動切り替え - 同じコードがリアルタイムとヒストリカルデータの両方で確定的な結果を生成するように。

そう、これはニュース取引にとって本当に悩ましい点だ。

ブラウザ、カレンダー、ターミナルを切り替えると、集中力が途切れて反応が遅くなる。ニュースを直接取引 環境に取り込む統一されたワークフローやシステムがあれば、執行がより速く、より一貫したものになるのは間違いない。

それをテストと自動化によって、構造化された再現可能な「エンジニアリング・スタイル」のセットアップに変えるというアイデアは、感情的な判断や遅れを避けるために、実に理にかなっている。

MQL5におけるイベント駆動型アーキテクチャ:エキスパートアドバイザーを本格的なトレードシステムに進化させる方法 MQL5におけるイベント駆動型アーキテクチャ:エキスパートアドバイザーを本格的なトレードシステムに進化させる方法
MQL5におけるイベント駆動アーキテクチャについて解説し、モノリシックなOnTickモデルから分散処理への移行を取り上げます。定義済みイベントとカスタムイベント、サービス、およびプログラム間のメッセージングについて説明するとともに、アーキテクチャ上でよく見られる典型的な誤りについても考察します。また、実践的な例を通じて、インジケータとEAの連携をどのように構成すれば、負荷を軽減し、可読性を向上させ、保守を容易にできるのかを示します。
Python-MetaTrader 5ストラテジーテスター(第1回):取引シミュレーター Python-MetaTrader 5ストラテジーテスター(第1回):取引シミュレーター
MetaTrader5のPythonモジュールは、Pythonを使ってMetaTrader5アプリで取引を発注するための便利な手段を提供しています。しかし、このモジュールには大きな問題があります。それは、MetaTrader5アプリに存在するストラテジーテスター機能が備わっていないことです。本連載では、Python環境で取引戦略をバックテストするためのフレームワークを構築していきます。
エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法 エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法
この記事では、MT4において複数のEAの衝突をさける方法を扱います。ターミナルの操作、MQL4の基本的な使い方がわかる人にとって、役に立つでしょう。
OpenCLを用いたMQL5におけるCPUからGPUへの実践的移行パス OpenCLを用いたMQL5におけるCPUからGPUへの実践的移行パス
MQL5でCPUからGPUへの移行方法を実用的に構築する方法を解説します。本記事では、コンテキストの初期化、バッファ構造の設計、大規模バッチ処理、カーネルの起動、データ転送の最小化に焦点を当てます。また、典型的なエラーとその解決方法についても取り上げます。ローソク足パターンの例を通じて、このアプローチの実用的な効果も示します。