English Deutsch
preview
ニュース取引が簡単に(第1回):データベースの作成

ニュース取引が簡単に(第1回):データベースの作成

MetaTrader 5 | 28 5月 2024, 09:12
324 0
Kabelo Frans Mampa
Kabelo Frans Mampa

はじめに

この記事では、MQL 5経済指標カレンダーのデータを格納するデータベースの作成方法について説明します。このデータは後に次回の記事で、ニュースの取引に使用することができます。また、このデータベースから特定の整理された情報を取得するために、基本的なSQLクエリを実行する方法を探ります。すべてのプロセスはMQL5のIDEでおこなわれます。

トレーダーは市場に影響を与えそうな情報がないか、ニュースソースを注視しています。これには、地政学的イベント、企業決算発表、政治イベント、GDP成長率や雇用統計などの経済レポートが含まれます。トレーダーは重要なニュースリリースに素早く対応し、その結果生じる市場の変化から利益を得ます。ニュースの解釈によっては、資産の売買が必要になるかもしれません。この記事では、MQL5経済指標カレンダーで簡単に入手できる経済イベントに焦点を当てます。


データベースを作る理由

データベース表の例


データベースとは、電子的に保存されアクセス可能な、構造化されたデータの集まりです。データベースは膨大な量のデータを効率的に管理保存することができ、データ分析、保存、管理といった様々な操作が可能です。MQL5では、SQLiteデータベースエンジンによって作成され管理されるSQLiteデータベースを使用します。SQLiteデータベースは任意のファイル拡張子を持つこともできますが、通常は.sqlite、.sqlite3、.dbの拡張子を持つ単一ディスクファイルです。これらのファイルには、表、トリガー、インデックス、その他のメタデータなど、データベースに存在するすべてのデータと構造が含まれています。

データベースは大規模なデータセットを扱うのに最適で、複雑なループを必要とせず、特定の日付やイベントからデータを取り出すプロセスを簡素化します。さらに、ストラテジーテスターではMQL5の経済指標カレンダーにアクセスできません。ニュースに基づいて戦略をテストしたい場合、どのようにすればいいのでしょうか。

データベースについての詳しい情報は、こちらの講義スライドおよび、より好ましくはこちらの MQL5記事をご覧ください。さらに、優れたSQLiteチュートリアルを追加しておきます。


MQL5経済指標カレンダーの通貨

番号 銘柄 名前
 1. NZD ニュージーランドドル
 2. EUR ユーロ
 3. JPY 日本円
 4. CAD カナダドル
 5. AUD 豪ドル
 6. CNY 人民元
 7. SGD シンガポールドル
 8. BRL ブラジルレアル
 9. MXN メキシコペソ
 10. ZAR 南アフリカランド
 11. HKD 香港ドル
 12. INR インドルピー
 13. NOK ノルウェークローネ
 14. USD 米ドル
 15. GBP ポンド
 16. CHF スイスフラン
 17. KRW 韓国ウォン
 18. SEK スウェーデンクローナ 

上の表は順不同です。

MQL5カレンダーで利用可能な通貨はいくつかありますが、証券会社で一般的に使用されていない通貨や、トレーダーが簡単にアクセスできない通貨もあります。例えば、ブラジルレアルや韓国ウォンはあまり流通していません。これらの珍しい通貨を扱う証券会社を見つけることができたとしても、スプレッドは通常、取引に不利です。私は個人的な経験から話しています。


データベースの作成

夏時間の概念

データベースを作成する前に、まず夏時間と、それがなぜバックテストに影響するのかを考えなければなりません。 夏時間(DST)とは、1年のうち暖かい時期、一般的には春から秋にかけて、日照時間を有効に利用し、エネルギーを節約するために時計を1時間進めることです。

夏時間が適用される地域では、春と秋の移行期間に現地時間が1時間変更されることがあります。これは金融市場の開閉時間に影響を与える可能性があります。例えば、夏時間が始まり、時計が1時間進むと、現地時間では市場が早く開く可能性があります。一方、夏時間が終了し、時計が1時間戻ると(通常時間)、市場の開く時間は現地時間では遅くなります。また、世界のさまざまな地域が、それぞれの季節に合わせて夏時間を設定できることも認識しなければなりません。

例えば、米国独自のDSTは、通常、毎年3月の第2日曜日に始まり、同年11月の第1日曜日に終わります。ヨーロッパ諸国の独自のDSTは、毎年3月の最終日曜日から10月の最終日曜日までです。オーストラリアも夏時間を実施する国として知られています。これは、通常、10月の第1日曜日に始まり、翌年の4月の第1日曜日に終わります。 

夏時間の調整を考慮し、一部の取引所や金融市場は取引スケジュールや時間帯を変更することがあります。取引所は、現地時間の変更を考慮した取引時間の変更、または取引所が実施する夏時間スケジュールに従ってタイムゾーンの調整を発表し、市場参加者の統一性と明確性を保証することができます。

私が観察したところでは、例えば証券会社が米国の夏時間を実践する場合、夏時間前のタイムゾーンはGMT+2となり、米国の夏時間が始まるとタイムゾーンはGMT+3に変更されます。米国の夏時間適用前または適用中に、証券会社のサーバーで発表される米国のニュースリリースの時間差に気づくことはないでしょう。そこで、米国のNFP(非農業部門雇用者数)イベントを例に説明します。NFPが米国夏時間前の証券会社サーバー時間の午後2時に発表されるとすると、タイムゾーンはGMT+3に変わったものの、時間は米国夏時間中の午後2時のままです。


英国夏時間取引セッションの時間変更


一方、英国の雇用ニュースリリースが、証券会社が米国の夏時間開始時にタイムゾーンを変更する英国と米国の夏時間開始前の午前8時であり、英国の雇用ニュースリリースが英国(EU)の夏時間開始前に発生した場合、英国の雇用ニュースリリースは証券会社の時間で午前7時となります。英国の夏時間が始まり、米国の夏時間と重なる場合、英国の雇用統計の発表は午前8時に戻ります。 

とてもややこしいことは承知していますが、後でバックテストするときにイベントが発生した正確な日付を知ることができるように、これをデータベースに実装します。幸運を祈りましょう。証券会社が米国の夏時間を使用しているのか、UK(EU)の夏時間を使用しているのか、オーストラリアの夏時間を使用しているのか、あるいは夏時間をまったく使用していないのかを判断する必要があります。また、夏時間の種類ごとに経済指標カレンダー表を作成し、教育目的でバックテストする時間割を変更できるようにします。 


実装

夏時間クラスは3つあります。

  • DaylightSavings_AU
  • DaylightSavings_UK
  • DaylightSavings_US
これらは互いに非常に似ており、すべてプロジェクトファイルに含まれるため、この記事では1つだけを扱います。

class CDaylightSavings_AU:CObject
  {

private:

   CTimeManagement   Time;
                     CDaylightSavings_AU(datetime startdate,datetime enddate);
   CObject           *List() { return savings;}//Gets the list of Daylight savings time
   datetime          StartDate;
   datetime          EndDate;
   CArrayObj         *savings;
   CArrayObj         *getSavings;
   CDaylightSavings_AU      *dayLight;

public:

                     CDaylightSavings_AU(void);
                    ~CDaylightSavings_AU(void);
   bool              isDaylightSavings(datetime Date);//This function checks if a given date falls within Daylight Savings Time.
   bool              DaylightSavings(int Year,datetime &startDate,datetime &endDate);//Check if Daylight Savings Dates are available for a certain Year
   void              adjustDaylightSavings(datetime EventDate,string &AdjustedDate);//Will adjust the date's time zone depending on Daylight Savings
  };


次のクラスを作成します。

CDaylightSavings_AU

これは次を継承しています。

CObject

このクラスは、MQL 5の経済指標カレンダーに保存されている最も古い日付である2007年からのすべての夏時間を保存するリストの作成から構成されます。

CDaylightSavings_AU::CDaylightSavings_AU(void)
  {
   savings = new CArrayObj();
//Daylight savings dates to readjust dates in the database for accurate testing in the strategy tester
   savings.Add(new CDaylightSavings_AU(D'2006.10.29 03:00:00',D'2007.03.25 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2007.10.28 03:00:00',D'2008.04.06 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2008.10.05 03:00:00',D'2009.04.05 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2009.10.04 03:00:00',D'2010.04.04 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2010.10.03 03:00:00',D'2011.04.03 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2011.10.02 03:00:00',D'2012.04.01 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2012.10.07 03:00:00',D'2013.04.07 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2013.10.06 03:00:00',D'2014.04.06 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2014.10.05 03:00:00',D'2015.04.05 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2015.10.04 03:00:00',D'2016.04.03 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2016.10.02 03:00:00',D'2017.04.02 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2017.10.01 03:00:00',D'2018.04.01 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2018.10.07 03:00:00',D'2019.04.07 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2019.10.06 03:00:00',D'2020.04.05 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2020.10.04 03:00:00',D'2021.04.04 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2021.10.03 03:00:00',D'2022.04.03 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2022.10.02 03:00:00',D'2023.04.02 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2023.10.01 03:00:00',D'2024.04.07 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2024.10.06 03:00:00',D'2025.04.06 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2025.10.05 03:00:00',D'2026.04.05 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2026.10.04 03:00:00',D'2027.04.04 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2027.10.03 03:00:00',D'2028.04.02 02:00:00'));
   savings.Add(new CDaylightSavings_AU(D'2028.10.01 03:00:00',D'2029.04.01 02:00:00'));
  }

次に、ブール関数を使用します。

bool              isDaylightSavings(datetime Date);//This function checks if a given date falls within Daylight Savings Time.

日付パラメータが夏時間期間内かどうかを判断します。

bool CDaylightSavings_AU::isDaylightSavings(datetime Date)
  {
// Initialize a list to store daylight savings periods.
   getSavings = List();
// Iterate through all the periods in the list.
   for(int i=0; i<getSavings.Total(); i++)
     {
      // Access the current daylight savings period.
      dayLight = getSavings.At(i);
      // Check if the given date is within the current daylight savings period.
      if(Time.DateIsInRange(dayLight.StartDate,dayLight.EndDate,Date))
        {
         // If yes, return true indicating it is daylight savings time.
         return true;
        }
     }
// If no period matches, return false indicating it is not daylight savings time.
   return false;
  }

また、別のブーリアン関数も使用します。

bool              DaylightSavings(int Year,datetime &startDate,datetime &endDate);//Adjusts time when it is daylight savings an hour behind if outside

上で初期化した「夏時間日付リスト」の中に「年」があるかどうかを判断するために、開始日と終了日を変数startDateとendDateに追加します。

bool CDaylightSavings_US::DaylightSavings(int Year,datetime &startDate,datetime &endDate)
  {
  // Initialize a list to store daylight savings periods.
   getSavings = List();
   bool startDateDetected=false,endDateDetected=false;
// Iterate through all the periods in the list.
   for(int i=0; i<getSavings.Total(); i++)
     {
      dayLight = getSavings.At(i);
      if(Year==Time.ReturnYear(dayLight.StartDate))//Check if a certain year's date is available within the Daylight Savings start dates in the List
        {
         startDate = dayLight.StartDate;
         startDateDetected = true;
        }
      if(Year==Time.ReturnYear(dayLight.EndDate))//Check if a certain year's date is available within the Daylight Savings end dates in the List
        {
         endDate = dayLight.EndDate;
         endDateDetected = true;
        }
      if(startDateDetected&&endDateDetected)//Check if both Daylight Savings start and end dates are found for a certain Year
        {
         return true;
        }
     }

   startDate = D'1970.01.01 00:00:00';//Set a default start date if no Daylight Saving date is found
   endDate = D'1970.01.01 00:00:00';//Set a default end date if no Daylight Saving date is found
   return false;
  }

このクラスの最後のpublic関数です。

void              adjustDaylightSavings(datetime EventDate,string &AdjustedDate);//Will adjust the date's time -zone depending on Daylight Savings

参照によって文字列変数AdjustedDateをEventDateで変更します。

void CDaylightSavings_AU::adjustDaylightSavings(datetime EventDate,string &AdjustedDate)
  {
   if(isDaylightSavings(TimeTradeServer()))//Check if the current trade server time is already within the Daylight Savings Period
     {
      if(isDaylightSavings(EventDate))//Checks if the event time is during daylight savings
        {
         AdjustedDate = TimeToString(EventDate);//storing normal event time
        }
      else
        {
         AdjustedDate = TimeToString((datetime)(EventDate-Time.HoursS()));//storing event time and removing an hour for DST
        }
     }
   else
     {
      if(isDaylightSavings(EventDate))//Checks if the event time is during daylight savings
        {
         AdjustedDate = TimeToString((datetime)(Time.HoursS()+EventDate));//storing event time and adding an hour for DST
        }
      else
        {
         AdjustedDate = TimeToString(EventDate);//storing normal event time
        }
     }
  }


次に、このプロジェクトにおける時間操作専用のヘッダーファイルに移ります。

CTimeManagement

これは同じプロジェクトのクラスです。

class CTimeManagement
  {

private:

   MqlDateTime       today;//private variable
   MqlDateTime       timeFormat;//private variable

public:

   bool              DateIsInRange(datetime FirstTime,datetime SecondTime,datetime compareTime);//Checks if a date is within two other dates
   bool              DateIsInRange(datetime Start,datetime End,datetime CompareStart,datetime CompareEnd);//Check if two dates(Start&End) are within CompareStart & CompareEnd
   bool              DateisToday(datetime TimeRepresented);//Checks if a date is within the current day
   int               SecondsS(int multiple=1);//Returns seconds
   int               MinutesS(int multiple=1);//Returns Minutes in seconds
   int               HoursS(int multiple=1);//Returns Hours in seconds
   int               DaysS(int multiple=1);//Returns Days in seconds
   int               WeeksS(int multiple=1);//Returns Weeks in seconds
   int               MonthsS(int multiple=1);//Returns Months in seconds
   int               YearsS(int multiple=1);//Returns Years in seconds
   int               ReturnYear(datetime time);//Returns the Year for a specific date
   datetime          TimeMinusOffset(datetime standardtime,int timeoffset);//Will return a datetime type of a date with an subtraction offset in seconds
   datetime          TimePlusOffset(datetime standardtime,int timeoffset);//Will return a datetime type of a date with an addition offset in seconds
  };


前に呼ばれた関数 

Time.DateIsInRange(dayLight.StartDate,dayLight.EndDate,Date)

は、ある日付が他の2つの日付の間にあるかどうかを確認する単純な関数です。

bool CTimeManagement::DateIsInRange(datetime FirstTime,datetime SecondTime,datetime compareTime)
  {
   if(FirstTime<=compareTime&&SecondTime>compareTime)
     {
      return true;
     }
   return false;
  }

同じ関数名でパラメータが異なる

bool		DateIsInRange(datetime Start,datetime End,datetime CompareStart,datetime CompareEnd);

は、2つの日付が他の日付の間にあるかどうかを確認します。

bool CTimeManagement::DateIsInRange(datetime Start,datetime End,datetime CompareStart,datetime CompareEnd)
  {
   if(Start<=CompareStart&&CompareEnd<End)
     {
      return true;
     }
   return false;
  }


ある日付が今日であるかどうかを知る関数が必要なので、

bool              DateisToday(datetime TimeRepresented);//Checks if a date is within the current day

を宣言します。これは、現在の時刻と日付の年、月、日を比較します。

bool CTimeManagement::DateisToday(datetime TimeRepresented)
  {
   MqlDateTime TiM;
   TimeToStruct(TimeRepresented,TiM);
   TimeCurrent(today);
   if(TiM.year==today.year&&TiM.mon==today.mon&&TiM.day==today.day)
     {
      return true;
     }
   return false;
  }


オフセット付きの日時を取得するには、

datetime          TimeMinusOffset(datetime standardtime,int timeoffset);//Will return a datetime type of a date with an subtraction offset in seconds

datetime          TimePlusOffset(datetime standardtime,int timeoffset);//Will return a datetime type of a date with an addition offset in seconds


の2つの関数があります。時間(または任意の時間単位)の負のオフセットを持つ日付を取得したい場合は、

datetime CTimeManagement::TimeMinusOffset(datetime standardtime,int timeoffset)
  {
   standardtime-=timeoffset;
   return standardtime;
  }

を使用します。一方、正のオフセットを持つ日付が欲しい場合は、次を使用します。

datetime CTimeManagement::TimePlusOffset(datetime standardtime,int timeoffset)
  {
   standardtime+=timeoffset;
   return standardtime;
  }



将来的には、グローバル変数や構造体、列挙型を格納するインクルードファイルを作成し、異なるクラスやEA間で使用できるようにすることにしました。

このインクルードファイルはCommonVariablesと呼ばれ、共通の変数を格納します。

string broker=AccountInfoString(ACCOUNT_COMPANY);//Getting brokers name via AccountInfoString
int Str = StringReplace(broker," ","");//Removing or replacing any spaces in the broker's name with an empty string
int Str1 = StringReplace(broker,".","");//Removing or replacing any dots in the broker's name with an empty string
int Str2 = StringReplace(broker,",","");//Removing or replacing any commas in the broker's name with an empty string
#define BROKER_NAME                    broker//Broker's Name
#define NEWS_TRADING_FOLDER            "NewsTrading"//Name of main folder in common/files
#define NEWS_CALENDAR_FOLDER           StringFormat("%s\\NewsCalendar",NEWS_TRADING_FOLDER)//name of subfolder in NewsTrading
#define NEWS_CALENDAR_BROKER_FOLDER    StringFormat("%s\\%s",NEWS_CALENDAR_FOLDER,BROKER_NAME)//Name of subfolder in NewsCalendar
#define NEWS_DATABASE_FILE             StringFormat("%s\\Calendar.sqlite",NEWS_CALENDAR_BROKER_FOLDER)//Name of sqlite file in subfolder in "Broker's Name"
#define NEWS_TEXT_FILE                 StringFormat("%s\\CalendarOpen.txt",NEWS_CALENDAR_BROKER_FOLDER)//Name of text file to indicate Calendar is open.

struct Calendar
  {
   ulong             EventId;//Event Id
   string            CountryName;//Event Country
   string            EventName;//Event Name
   string            EventType;//Event Type
   string            EventImportance;//Event Importance
   string            EventDate;//Event Date
   string            EventCurrency;//Event Currency
   string            EventCode;//Event Code
   string            EventSector;//Event Sector
   string            EventForecast;//Event Forecast Value
   string            EventPreval;//Event Previous Value
   string            EventImpact;//Event Impact
   string            EventFrequency;//Event Frequency
  };

enum DST_type
  {
   US_DST,//US Daylight Savings
   UK_DST,//UK(EU) Daylight Savings
   AU_DST,//AU Daylight Savings
   DST_NONE//No Daylight Savings Available
  };



Commonファイルフォルダにファイルを作成する際、フォルダごとにファイルを整理して、Commonファイルフォルダを通して簡単に調整できるようにしたいです。

そこで

class CFolders

クラスを作成しました。これにより、CommonファイルフォルダにNewsTrading/NewsCalendar/Brokerという順番でフォルダが作成されます。クラスのコンストラクタにこのタスクを実行させます。

class CFolders
  {
private:
   bool              CreateFolder(string FolderPath);//Will create a folder with the FolderPath string parameter

public:
                     CFolders(void);//Class's constructor
  };

コンストラクタ内で

CFolders::CFolders(void)
  {
   if(CreateFolder(NEWS_TRADING_FOLDER))//Will create the NewsTrading Folder
     {
      if(CreateFolder(NEWS_CALENDAR_FOLDER))//Will create the NewsCalendar Folder
        {
         if(!CreateFolder(NEWS_CALENDAR_BROKER_FOLDER))//Will create the Broker Folder
           {
            Print("Something went wrong with creating folder: ",NEWS_CALENDAR_BROKER_FOLDER);
           }
        }
     }
  }

個々のフォルダを作成するためにコンストラクタで呼び出される関数

bool CFolders::CreateFolder(string FolderPath)
  {
//--- attempt to create a folder relative to the MQL5\Files path
   if(FolderCreate(FolderPath,FILE_COMMON))
     {
      //--- successful execution
      return true;
     }
   else
     {
      PrintFormat("Failed to create the folder %s. Error code %d",FolderPath,GetLastError());
     }
//--- execution failed
   return false;
  }



ローソク足は非常に重要で、特定のローソク足の高値、安値、始値、終値に関する情報を収集する必要があります。そのために、プロジェクト内の他のプログラムで必要なときにこの情報を収集する別のクラスを作成します。クラス名は

class CCandleProperties

です。このクラスで関数を宣言します。

class CCandleProperties
  {
private:
   CTimeManagement   Time;

public:
   double            Open(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle OpenPrice
   double            Close(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle ClosePrice
   double            High(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle HighPrice
   double            Low(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle LowPrice
   bool              IsLargerThanPreviousAndNext(datetime CandleTime,int Offset,string SYMBOL);//Determine if one candle is larger than two others
  };

次をざっと見てみましょう。

double            Open(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL);//Retrieve Candle Open Price

この関数では、整数のCandleIndexパラメータとローソク足の時間枠、およびローソク足の銘柄に基づいて、ローソク足の始値を返します。

double CCandleProperties::Open(int CandleIndex,ENUM_TIMEFRAMES Period=PERIOD_CURRENT,string SYMBOL=NULL)
  {
   return iOpen(((SYMBOL==NULL)?Symbol():SYMBOL),Period,CandleIndex);//return candle open price
  }

証券会社は時間帯をずらす可能性があるため、経済イベントが特定の日付に起こったかどうかを確認するためです。経済イベントの日付を取得し、この日付でその時間のM15ローソク足を調べ、ローソク足の高さ(iHigh-iLow)を計算し、この高さをイベントの1時間前と1時間後のM15ローソク足と比較します。通常、経済イベントでは市場価格の変動が非常に大きいため、イベントが発生したときは非常に長いローソク足に気づくはずです。市場がこの長いローソクを形成するのに十分な時間を与える可能性が高い、M15ローソク足を使用します。証券会社がタイムゾーンを移動した場合、MQL5経済指標カレンダーに保存されたイベント日付は、証券会社のローソク足の特定時刻のボラティリティと一致しない可能性がありますが、このボラティリティは、指定された日付の1時間後または1時間前に存在する可能性があります。このバリデーション確認に使用する関数は次のとおりです。

bool              IsLargerThanPreviousAndNext(datetime CandleTime,int Offset,string SYMBOL);//Determine if one candle is larger than two others

この関数は、特定の日付のローソク足の高さが、この指定された日付の前後に時間オフセットがあるローソク足よりも大きいかどうかを調べます。

bool CCandleProperties::IsLargerThanPreviousAndNext(datetime CandleTime,int Offset,string SYMBOL)
  {
   int CandleIndex = iBarShift(SYMBOL,PERIOD_M15,CandleTime);//Assign candle index of candletime
   int CandleIndexMinusOffset = iBarShift(SYMBOL,PERIOD_M15,Time.TimeMinusOffset(CandleTime,Offset));//Assign candle index of candletime minus time offset 
   int CandleIndexPlusOffset = iBarShift(SYMBOL,PERIOD_M15,Time.TimePlusOffset(CandleTime,Offset));//Assign candle index of candletime plus time offset
   double CandleHeight = High(CandleIndex,PERIOD_M15,SYMBOL)-Low(CandleIndex,PERIOD_M15,SYMBOL);//Assign height of M15 candletime in pips
   double CandleHeightMinusOffset = High(CandleIndexMinusOffset,PERIOD_M15,SYMBOL)-Low(CandleIndexMinusOffset,PERIOD_M15,SYMBOL);//Assign height of M15 candletime  minus offset in Pips
   double CandleHeightPlusOffset = High(CandleIndexPlusOffset,PERIOD_M15,SYMBOL)-Low(CandleIndexPlusOffset,PERIOD_M15,SYMBOL);//Assign height of M15 candletime plus offset in Pips
   //--Determine if candletime height is greater than candletime height minus offset and candletime height plus offset
   if(CandleHeight>CandleHeightMinusOffset&&CandleHeight>CandleHeightPlusOffset)
     {
      return true;//Candletime is likely when the news event occurred
     }
   return false;//Candletime is unlikely when the real news data was released
  }



Newsクラスに進みます。 このクラスは、MQL 5経済指標カレンダーから値を取得し、

テストと最終的には取引のためにその値をデータベースに保存することを直接処理します。 

class CNews
  {
   //Private Declarations Only accessible by this class/header file
private:
   CTimeManagement   Time;//TimeManagement Object declaration
   CDaylightSavings_UK  Savings_UK;//DaylightSavings Object for the UK and EU
   CDaylightSavings_US  Savings_US;//DaylightSavings Object for the US
   CDaylightSavings_AU  Savings_AU;//DaylightSavings Object for the AU
   CCandleProperties Candle;//CandleProperties Object
   string            CurrencyBase,CurrencyProfit,EURUSD;//String variables declarations for working with EURUSD
   bool              EurusdIsSelected,EurusdIsFound,is_Custom;//Boolean variables declarations for working with EURUSD
   bool              timeIsShifted;//Boolean variable declaration will be used to determine if the broker changes it's time zone
   datetime          DaylightStart,DaylightEnd;//Datetime variables declarations for start and end dates for Daylight Savings
   //Structure Declaration for DST
   struct DST
     {
      bool           result;
      datetime       date;
     };
   bool              AutoDetectDST(DST_type &dstType);//Function will determine Broker DST
   DST_type          DSTType;//variable of DST_type enumeration declared in the CommonVariables class/header file
   bool              InsertIntoTable(int db,DST_type Type,Calendar &Evalues[]);//Function for inserting Economic Data in to a database's table
   void              CreateAutoDST(int db);//Function for creating and inserting Recommend DST for the Broker into a table
   bool              CreateTable(int db,string tableName,bool &tableExists);//Function for creating a table in a database
   void              CreateRecords(int db);//Creates a table to store records of when last the Calendar database was updated/created
   bool              UpdateRecords();//Checks if the main Calendar database needs an update or not
   void              EconomicDetails(Calendar &NewsTime[]);//Gets values from the MQL5 economic Calendar

   //Public declarations accessable via a class's Object
public:
                    ~CNews(void);//Deletes a text file created when the Calendar database is being worked on
   void              CreateEconomicDatabase();//Creates the Calendar database for a specific Broker
   datetime          GetLastestNewsDate();//Gets the latest/newest date in the Calendar database
  };


ここでは、まず、 

bool              AutoDetectDST(DST_type &dstType);//Function will determine Broker DST

を見てみましょう。名前にあるように、この関数の主な目的は、証券会社が使用するDSTスケジュールを取得することです。この情報は、列挙で取得します。

enum DST_type
  {
   US_DST,//US Daylight Savings
   UK_DST,//UK(EU) Daylight Savings
   AU_DST,//AU Daylight Savings
   DST_NONE//No Daylight Savings Available
  };

AutoDectDST関数で参照渡しされるこの関数は、証券会社の夏時間スケジュールが既知であるか、または認識できなかった場合にfalseを返します。

bool CNews::AutoDetectDST(DST_type &dstType)
  {
   MqlCalendarValue values[];//Single array of MqlCalendarValue type
   string eventtime[];//Single string array variable to store NFP(Nonfarm Payrolls) dates for the 'United States' from the previous year
   int lastyear = Time.ReturnYear(Time.TimeMinusOffset(iTime(Symbol(),PERIOD_CURRENT,0),Time.YearsS()));//Will store the previous year into an integer
   datetime lastyearstart = StringToTime(StringFormat("%s.01.01 00:00:00",(string)lastyear));//Will store the start date for the previous year
   datetime lastyearend = StringToTime(StringFormat("%s.12.31 23:59:59",(string)lastyear));//Will store the end date for the previous year

   if(CalendarValueHistory(values,lastyearstart,lastyearend,"US"))//Getting last year's calendar values for CountryCode = 'US'
     {
      for(int x=0; x<(int)ArraySize(values); x++)
        {
         if(values[x].event_id==840030016)//Get only NFP Event Dates
           {
            ArrayResize(eventtime,eventtime.Size()+1,eventtime.Size()+2);//Increasing the size of eventtime array by 1
            eventtime[eventtime.Size()-1] = TimeToString(values[x].time);//Storing the dates in an array of type string
           }
        }
     }

   datetime ShiftStart=D'1970.01.01 00:00:00',ShiftEnd=D'1970.01.01 00:00:00';//datetime variables to store the broker's time zone shift(change)
   DST previousresult,currentresult;//Variables of structure type DST declared at the beginning of the class

   EURUSD="";//String variable assigned empty string
   EurusdIsSelected = false;//Boolean variable assigned value false
   EurusdIsFound = false;//Boolean variable assigned value false

   for(int i=0;i<SymbolsTotal(true);i++)//Will loop through all the Symbols inside the Market Watch
     {
      string SymName = SymbolName(i,true);//Assign the Symbol Name of index 'i' from the list of Symbols inside the Market Watch
      CurrencyBase = SymbolInfoString(SymName,SYMBOL_CURRENCY_BASE);//Assign the Symbol's Currency Base
      CurrencyProfit = SymbolInfoString(SymName,SYMBOL_CURRENCY_PROFIT);//Assign the Symbol's Currency Profit
      SymbolExist(SymName,is_Custom);//Get the boolean value into 'is_Custom' for whether the Symbol Name is a Custom Symbol(Is not from the broker)

      //-- Check if the Symbol outside the Market Watch has a SYMBOL_CURRENCY_BASE of EUR
      //-- and a SYMBOL_CURRENCY_PROFIT of USD, and this Symbol is not a Custom Symbol(Is not from the broker)
      if(CurrencyBase=="EUR"&&CurrencyProfit=="USD"&&!is_Custom)
        {
         EURUSD = SymName;//Assigning the name of the EURUSD Symbol found inside the Market Watch
         EurusdIsFound = true;//EURUSD Symbol was found in the Trading Terminal for your Broker
         break;//Will end the for loop
        }
     }

   if(!EurusdIsFound)//Check if EURUSD Symbol was already Found in the Market Watch
     {
      for(int i=0; i<SymbolsTotal(false); i++)//Will loop through all the available Symbols outside the Market Watch
        {
         string SymName = SymbolName(i,false);//Assign the Symbol Name of index 'i' from the list of Symbols outside the Market Watch
         CurrencyBase = SymbolInfoString(SymName,SYMBOL_CURRENCY_BASE);
         CurrencyProfit = SymbolInfoString(SymName,SYMBOL_CURRENCY_PROFIT);
         SymbolExist(SymName,is_Custom);//Get the boolean value into 'is_Custom' for whether the Symbol Name is a Custom Symbol(Is not from the broker)

         //-- Check if the Symbol outside the Market Watch has a SYMBOL_CURRENCY_BASE of EUR
         //-- and a SYMBOL_CURRENCY_PROFIT of USD, and this Symbol is not a Custom Symbol(Is not from the broker)
         if(CurrencyBase=="EUR"&&CurrencyProfit=="USD"&&!is_Custom)
           {
            EurusdIsSelected = SymbolSelect(SymName,true);//Adding the EURUSD Symbol to the Market Watch
            if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch
              {
               EURUSD = SymName;//Assigning the name of the EURUSD Symbol found outside the Market Watch
               EurusdIsFound = true;//EURUSD Symbol was found in the Trading Terminal for your Broker
               break;//Will end the for loop
              }
           }
        }
     }

   if(!EurusdIsFound)//Check if EURUSD Symbol was Found in the Trading Terminal for your Broker
     {
      Print("Cannot Find EURUSD!");
      Print("Cannot Create Database!");
      Print("Server DST Cannot be Detected!");
      dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time)
      return false;//Returning False, Broker's DST schedule was not found
     }

   for(uint i=0;i<eventtime.Size();i++)
     {
      currentresult.result = Candle.IsLargerThanPreviousAndNext((datetime)eventtime[i],Time.HoursS(),EURUSD);//Store the result of if the event date is the larger candlestick
      currentresult.date = (datetime)eventtime[i];//Store the eventdate from eventtime[i]
      timeIsShifted = ((currentresult.result!=previousresult.result&&i>0)?true:false);//Check if there is a difference between the previous result and the current result

      //--- Print Event Dates and if the event date's candle is larger than the previous candle an hour ago and the next candle an hour ahead
      Print("Date: ",eventtime[i]," is Larger: ",Candle.IsLargerThanPreviousAndNext((datetime)eventtime[i],Time.HoursS(),EURUSD)," Shifted: ",timeIsShifted);

      if(timeIsShifted)//Check if the Larger candle has shifted from the previous event date to the current event date in eventtime[i] array
        {
         if(ShiftStart==D'1970.01.01 00:00:00')//Check if the ShiftStart variable has not been assigned a relevant value yet
           {
            ShiftStart=currentresult.date;//Store the event date for when the time shift began
           }
         ShiftEnd=previousresult.date;//Store the event date timeshift
        }
      previousresult.result = currentresult.result;//Store the previous result of if the event date is the larger candlestick
      previousresult.date = currentresult.date;//Store the event date from eventtime[i]
     }

   if(ShiftStart==D'1970.01.01 00:00:00'&&eventtime.Size()>0)//Check if the ShiftStart variable has not been assigned a relevant value and the event dates are more than zero
     {
      Print("Broker ServerTime unchanged!");
      dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time)
      return true;//Returning True, Broker's DST schedule was found successfully
     }

   if(Savings_AU.DaylightSavings(lastyear,DaylightStart,DaylightEnd))
     {
      if(Time.DateIsInRange(DaylightStart,DaylightEnd,ShiftStart,ShiftEnd))
        {
         Print("Broker ServerTime Adjusted For AU DST");
         if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch
           {
            SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch
           }
         dstType = AU_DST;//Assigning enumeration value AU_DST, Broker has AU DST(Daylight Savings Time)
         return true;//Returning True, Broker's DST schedule was found successfully
        }
     }
   else
     {
      Print("Something went wrong!");
      Print("Cannot Find Daylight-Savings Date For AU");
      Print("Year: %d Cannot Be Found!",lastyear);
      if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch
        {
         SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch
        }
      dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time)
      return false;//Returning False, Broker's DST schedule was not found
     }

   if(Savings_UK.DaylightSavings(lastyear,DaylightStart,DaylightEnd))
     {
      if(Time.DateIsInRange(DaylightStart,DaylightEnd,ShiftStart,ShiftEnd))
        {
         Print("Broker ServerTime Adjusted For UK DST");
         if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch
           {
            SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch
           }
         dstType = UK_DST;//Assigning enumeration value UK_DST, Broker has UK/EU DST(Daylight Savings Time)
         return true;//Returning True, Broker's DST schedule was found successfully
        }
     }
   else
     {
      Print("Something went wrong!");
      Print("Cannot Find Daylight-Savings Date For UK");
      Print("Year: %d Cannot Be Found!",lastyear);
      if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch
        {
         SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch
        }
      dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time)
      return false;//Returning False, Broker's DST schedule was not found
     }

   if(Savings_US.DaylightSavings(lastyear,DaylightStart,DaylightEnd))
     {
      if(Time.DateIsInRange(DaylightStart,DaylightEnd,ShiftStart,ShiftEnd))
        {
         Print("Broker ServerTime Adjusted For US DST");
         if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch
           {
            SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch
           }
         dstType = US_DST;//Assigning enumeration value US_DST, Broker has US DST(Daylight Savings Time)
         return true;//Returning True, Broker's DST schedule was found successfully
        }
     }
   else
     {
      Print("Something went wrong!");
      Print("Cannot Find Daylight-Savings Date For US");
      Print("Year: %d Cannot Be Found!",lastyear);
      if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch
        {
         SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch
        }
      dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time)
      return false;//Returning False, Broker's DST schedule was not found
     }

   if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch
     {
      SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch
     }
   Print("Cannot Detect Broker ServerTime Configuration!");
   dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time)
   return false;//Returning False, Broker's DST schedule was not found
  }


さて、上の関数は長いので、分解してみましょう。最初の部分では、前年のNFPの経済イベントの日付を収集します。つまり、今年が2024年であれば、2023年のすべての日付を収集することになります。証券会社が夏時間を実施する可能性の高いスケジュールを得るためには、1年を通して分析する必要があるからです。これらの日付は単一の文字列配列eventtimeに格納されます。 

MqlCalendarValue values[];//Single array of MqlCalendarValue type
   string eventtime[];//Single string array variable to store NFP(Nonfarm Payrolls) dates for the 'United States' from the previous year
   int lastyear = Time.ReturnYear(Time.TimeMinusOffset(iTime(Symbol(),PERIOD_CURRENT,0),Time.YearsS()));//Will store the previous year into an integer
   datetime lastyearstart = StringToTime(StringFormat("%s.01.01 00:00:00",(string)lastyear));//Will store the start date for the previous year
   datetime lastyearend = StringToTime(StringFormat("%s.12.31 23:59:59",(string)lastyear));//Will store the end date for the previous year

   if(CalendarValueHistory(values,lastyearstart,lastyearend,"US"))//Getting last year's calendar values for CountryCode = 'US'
     {
      for(int x=0; x<(int)ArraySize(values); x++)
        {
         if(values[x].event_id==840030016)//Get only NFP Event Dates
           {
            ArrayResize(eventtime,eventtime.Size()+1,eventtime.Size()+2);//Increasing the size of event time array by 1
            eventtime[eventtime.Size()-1] = TimeToString(values[x].time);//Storing the dates in an array of type string
           }
        }
     }


次に、これらの日付をEURUSD銘柄に使用する必要があります。XAUUSD(金)やUS30(ダウジョーンズ)などの他の指数は、ニュースイベントがなくても非常に不安定ですが、EURUSDはほぼ安定しているが経済イベント中は非常に不安定になるためです。これが簡単になります。これにより、イベントによって市場が急騰する可能性が高いため、経済イベントがいつ発生したかを検出しやすくなります。NFPは定期的に相場を急騰させるため、私たちがNFPに注目する理由もここにあります。したがって、この情報を使用すると、EURUSD銘柄が必要になります。まず、証券会社で利用可能なすべての銘柄を確認してEURUSDを見つけ、それを選択します。EURUSDが見つからなければfalseを返します。 

   EURUSD="";//String variable assigned empty string
   EurusdIsSelected = false;//Boolean variable assigned value false
   EurusdIsFound = false;//Boolean variable assigned value false

   for(int i=0;i<SymbolsTotal(true);i++)//Will loop through all the Symbols inside the Market Watch
     {
      string SymName = SymbolName(i,true);//Assign the Symbol Name of index 'i' from the list of Symbols inside the Market Watch
      CurrencyBase = SymbolInfoString(SymName,SYMBOL_CURRENCY_BASE);//Assign the Symbol's Currency Base
      CurrencyProfit = SymbolInfoString(SymName,SYMBOL_CURRENCY_PROFIT);//Assign the Symbol's Currency Profit
      SymbolExist(SymName,is_Custom);//Get the boolean value into 'is_Custom' for whether the Symbol Name is a Custom Symbol(Is not from the broker)

      //-- Check if the Symbol outside the Market Watch has a SYMBOL_CURRENCY_BASE of EUR
      //-- and a SYMBOL_CURRENCY_PROFIT of USD, and this Symbol is not a Custom Symbol(Is not from the broker)
      if(CurrencyBase=="EUR"&&CurrencyProfit=="USD"&&!is_Custom)
        {
         EURUSD = SymName;//Assigning the name of the EURUSD Symbol found inside the Market Watch
         EurusdIsFound = true;//EURUSD Symbol was found in the Trading Terminal for your Broker
         break;//Will end the for loop
        }
     }

   if(!EurusdIsFound)//Check if EURUSD Symbol was already Found in the Market Watch
     {
      for(int i=0; i<SymbolsTotal(false); i++)//Will loop through all the available Symbols outside the Market Watch
        {
         string SymName = SymbolName(i,false);//Assign the Symbol Name of index 'i' from the list of Symbols outside the Market Watch
         CurrencyBase = SymbolInfoString(SymName,SYMBOL_CURRENCY_BASE);
         CurrencyProfit = SymbolInfoString(SymName,SYMBOL_CURRENCY_PROFIT);
         SymbolExist(SymName,is_Custom);//Get the boolean value into 'is_Custom' for whether the Symbol Name is a Custom Symbol(Is not from the broker)

         //-- Check if the Symbol outside the Market Watch has a SYMBOL_CURRENCY_BASE of EUR
         //-- and a SYMBOL_CURRENCY_PROFIT of USD, and this Symbol is not a Custom Symbol(Is not from the broker)
         if(CurrencyBase=="EUR"&&CurrencyProfit=="USD"&&!is_Custom)
           {
            EurusdIsSelected = SymbolSelect(SymName,true);//Adding the EURUSD Symbol to the Market Watch
            if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch
              {
               EURUSD = SymName;//Assigning the name of the EURUSD Symbol found outside the Market Watch
               EurusdIsFound = true;//EURUSD Symbol was found in the Trading Terminal for your Broker
               break;//Will end the for loop
              }
           }
        }
     }

   if(!EurusdIsFound)//Check if EURUSD Symbol was Found in the Trading Terminal for your Broker
     {
      Print("Cannot Find EURUSD!");
      Print("Cannot Create Database!");
      Print("Server DST Cannot be Detected!");
      dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time)
      return false;//Returning False, Broker's DST schedule was not found
     }


EURUSDを見つけた後、すべてのNFPの日付を繰り返し、個々の日付のM15ローソク足を見つけ、ローソク足の高さをイベントの前後1時間のオフセット日付と比較し、イベントが発生した可能性が高いことを検出します。イベント日付がローソク足のボラティリティと一致しない場合、この不一致が発生した最初のイベント日付と、それが終了した日付を変数ShiftStartとShiftEndに格納します。

for(uint i=0;i<eventtime.Size();i++)
     {
      currentresult.result = Candle.IsLargerThanPreviousAndNext((datetime)eventtime[i],Time.HoursS(),EURUSD);//Store the result of if the event date is the larger candlestick
      currentresult.date = (datetime)eventtime[i];//Store the event date from eventtime[i]
      timeIsShifted = ((currentresult.result!=previousresult.result&&i>0)?true:false);//Check if there is a difference between the previous result and the current result

      //--- Print Event Dates and if the event date's candle is larger than the previous candle an hour ago and the next candle an hour ahead
      Print("Date: ",eventtime[i]," is Larger: ",Candle.IsLargerThanPreviousAndNext((datetime)eventtime[i],Time.HoursS(),EURUSD)," Shifted: ",timeIsShifted);

      if(timeIsShifted)//Check if the Larger candle has shifted from the previous event date to the current event date in eventtime[i] array
        {
         if(ShiftStart==D'1970.01.01 00:00:00')//Check if the ShiftStart variable has not been assigned a relevant value yet
           {
            ShiftStart=currentresult.date;//Store the event date for when the time shift began
           }
         ShiftEnd=previousresult.date;//Store the event date timeshift
        }
      previousresult.result = currentresult.result;//Store the previous result of if the event date is the larger candlestick
      previousresult.date = currentresult.date;//Store the event date from eventtime[i]
     }


ShiftStartとShiftEndの日付を得た後、日付がDSTの開始日と終了日のいずれかに対応しているかどうかを確認します。対応があった場合、変数dstType内のDSTスケジュールを割り当ててtrueを返します。もしShiftStartの日付(ShiftStart=D'1970.01.01 00:00:00')がなく、配列eventtimeのサイズが0以上であれば、証券会社は夏時間スケジュールに従っていないことがわかります。

if(ShiftStart==D'1970.01.01 00:00:00'&&eventtime.Size()>0)//Check if the ShiftStart variable has not been assigned a relevant value and the event dates are more than zero
     {
      Print("Broker ServerTime unchanged!");
      dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time)
      return true;//Returning True, Broker's DST schedule was found successfully
     }

   if(Savings_AU.DaylightSavings(lastyear,DaylightStart,DaylightEnd))
     {
      if(Time.DateIsInRange(DaylightStart,DaylightEnd,ShiftStart,ShiftEnd))
        {
         Print("Broker ServerTime Adjusted For AU DST");
         if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch
           {
            SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch
           }
         dstType = AU_DST;//Assigning enumeration value AU_DST, Broker has AU DST(Daylight Savings Time)
         return true;//Returning True, Broker's DST schedule was found successfully
        }
     }
   else
     {
      Print("Something went wrong!");
      Print("Cannot Find Daylight-Savings Date For AU");
      Print("Year: %d Cannot Be Found!",lastyear);
      if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch
        {
         SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch
        }
      dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time)
      return false;//Returning False, Broker's DST schedule was not found
     }

   if(Savings_UK.DaylightSavings(lastyear,DaylightStart,DaylightEnd))
     {
      if(Time.DateIsInRange(DaylightStart,DaylightEnd,ShiftStart,ShiftEnd))
        {
         Print("Broker ServerTime Adjusted For UK DST");
         if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch
           {
            SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch
           }
         dstType = UK_DST;//Assigning enumeration value UK_DST, Broker has UK/EU DST(Daylight Savings Time)
         return true;//Returning True, Broker's DST schedule was found successfully
        }
     }
   else
     {
      Print("Something went wrong!");
      Print("Cannot Find Daylight-Savings Date For UK");
      Print("Year: %d Cannot Be Found!",lastyear);
      if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch
        {
         SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch
        }
      dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time)
      return false;//Returning False, Broker's DST schedule was not found
     }

   if(Savings_US.DaylightSavings(lastyear,DaylightStart,DaylightEnd))
     {
      if(Time.DateIsInRange(DaylightStart,DaylightEnd,ShiftStart,ShiftEnd))
        {
         Print("Broker ServerTime Adjusted For US DST");
         if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch
           {
            SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch
           }
         dstType = US_DST;//Assigning enumeration value US_DST, Broker has US DST(Daylight Savings Time)
         return true;//Returning True, Broker's DST schedule was found successfully
        }
     }
   else
     {
      Print("Something went wrong!");
      Print("Cannot Find Daylight-Savings Date For US");
      Print("Year: %d Cannot Be Found!",lastyear);
      if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch
        {
         SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch
        }
      dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time)
      return false;//Returning False, Broker's DST schedule was not found
     }

   if(EurusdIsSelected)//Check if this program added EURUSD Symbol to Market Watch
     {
      SymbolSelect(EURUSD,false);//Remove EURUSD Symbol from Market Watch
     }
   Print("Cannot Detect Broker ServerTime Configuration!");
   dstType = DST_NONE;//Assigning enumeration value DST_NONE, Broker has no DST(Daylight Savings Time)
   return false;//Returning False, Broker's DST schedule was not found
  }


夏時間のスケジュールを検出したら、この情報を保存しておき、後で経済イベントをテストするときに、どのカレンダーを使用するべきかを知ることができます。

void              CreateAutoDST(int db);//Function for creating and inserting Recommend DST for the Broker into a table

1つのレコードがAutoDST表に格納されます。

void CNews::CreateAutoDST(int db)
  {
   bool failed=false;//boolean variable

   if(!DatabaseTableExists(db,"AutoDST"))//Checks if the table 'AutoDST' exists in the databse 'Calendar'
     {
      //--- create the table AutoDST
      if(!DatabaseExecute(db,"CREATE TABLE AutoDST(DST STRING NOT NULL);"))//Will attempt to create the table 'AutoDST'
        {
         Print("DB: create the AutoDST table failed with code ", GetLastError());
         DatabaseClose(db);//Close the database
         return;//Exits the function if creating the table failed
        }
     }
   else
     {
      return;//Exits the function if the table AutoDST table already exists
     }

//Sql query/request to insert the recommend DST for the Broker using the DSTType variable to determine which string data to insert
   string request_text=StringFormat("INSERT INTO 'AutoDST'(DST) VALUES ('%s')",((DSTType==US_DST)?"Data_US":
                                    (DSTType==UK_DST)?"Data_UK":(DSTType==AU_DST)?"Data_AU":"Data_None"));

   if(!DatabaseExecute(db, request_text))//Will attempt to run this sql request/query
     {
      Print(GetLastError());
      PrintFormat("INSERT INTO 'AutoDST'(DST) VALUES ('%s')",((DSTType==US_DST)?"Data_US":
                  (DSTType==UK_DST)?"Data_UK":(DSTType==AU_DST)?"Data_AU":"Data_None"));//Will print the sql query if failed
      failed=true;//assign true if the request failed
     }

   if(failed)
     {
      //--- roll back all transactions and unlock the database
      DatabaseTransactionRollback(db);
      PrintFormat("%s: DatabaseExecute() failed with code %d", __FUNCTION__, GetLastError());
     }
  }


カレンダーの表を作成する関数が必要なので、この関数を再利用して、異なる夏時間スケジュールに合わせて個々のカレンダーを調整することができます。

bool              CreateTable(int db,string tableName,bool &tableExists);//Function for creating a table in a database

このCreateTable関数では、UK DST用の表Data_UK、US DST用の表Data_US、AU DST用の表Data_AU、None DST用の表Data_Noneを作成します。文字列tableNameは、表の接尾辞名のパラメータとなります。

bool CNews::CreateTable(int db,string tableName,bool &tableExists)
  {
   if(DatabaseTableExists(db,StringFormat("Data_%s",tableName)))//Checks if a table 'Data_%s' exists in the database 'Calendar'
     {
      tableExists=true;//Assigns true to tableExists variable

      if(!DatabaseExecute(db,StringFormat("DROP TABLE Data_%s",tableName)))//We will drop the table if the table already exists
        {
         //If the table failed to be dropped/deleted
         PrintFormat("Failed to drop table Data_%s with code %d",tableName,GetLastError());
         DatabaseClose(db);//Close the database
         return false;//will terminate execution of the rest of the code below and return false, when the table cannot be dropped
        }
     }

   if(!DatabaseTableExists(db,StringFormat("Data_%s",tableName)))//If the database table 'Data_%s' doesn't exist
     {
      //--- create the table 'Data' with the following columns
      if(!DatabaseExecute(db,StringFormat("CREATE TABLE Data_%s("
                                          "ID INT NOT NULL,"
                                          "EVENTID  INT   NOT NULL,"
                                          "COUNTRY  STRING   NOT NULL,"
                                          "EVENTNAME   STRING   NOT NULL,"
                                          "EVENTTYPE   STRING   NOT NULL,"
                                          "EVENTIMPORTANCE   STRING   NOT NULL,"
                                          "EVENTDATE   STRING   NOT NULL,"
                                          "EVENTCURRENCY  STRING   NOT NULL,"
                                          "EVENTCODE   STRING   NOT NULL,"
                                          "EVENTSECTOR STRING   NOT NULL,"
                                          "EVENTFORECAST  STRING   NOT NULL,"
                                          "EVENTPREVALUE  STRING   NOT NULL,"
                                          "EVENTIMPACT STRING   NOT NULL,"
                                          "EVENTFREQUENCY STRING   NOT NULL,"
                                          "PRIMARY KEY(ID));",tableName)))//Checks if the table was successfully created
        {
         Print("DB: create the Calendar table failed with code ", GetLastError());
         DatabaseClose(db);//Close the database
         return false;//Function returns false if creating the table failed
        }
     }
   return true;//Function returns true if creating the table was successful
  }


次に、作成した表にデータを挿入する必要がありますが、その前にデータを取得する必要があります。次の関数

void              EconomicDetails(Calendar &NewsTime[]);//Gets values from the MQL5 economic Calendar

利用可能なすべての経済イベントを、NewsTime Calendar配列を参照して取得します。

void CNews::EconomicDetails(Calendar &NewsTime[])
  {
   int Size=0;//to keep track of the size of the events in the NewsTime array
   MqlCalendarCountry countries[];
   int count=CalendarCountries(countries);//Get the array of country names available in the Calendar
   string Country_code="";

   for(int i=0; i<count; i++)
     {
      MqlCalendarValue values[];
      datetime date_from=0;//Get date from the beginning
      datetime date_to=(datetime)(Time.MonthsS()+iTime(Symbol(),PERIOD_D1,0));//Date of the next month from the current day

      if(CalendarValueHistory(values,date_from,date_to,countries[i].code))
        {
         for(int x=0; x<(int)ArraySize(values); x++)
           {
            MqlCalendarEvent event;
            ulong event_id=values[x].event_id;//Get the event id

            if(CalendarEventById(event_id,event))
              {
               ArrayResize(NewsTime,Size+1,Size+2);//Readjust the size of the array to +1 of the array size
               StringReplace(event.name,"'","");//Removing or replacing single quotes(') from event name with an empty string

               NewsTime[Size].CountryName = countries[i].name;//storing the country's name from the specific event
               NewsTime[Size].EventName = event.name;//storing the event's name
               NewsTime[Size].EventType = EnumToString(event.type);//storing the event type from (ENUM_CALENDAR_EVENT_TYPE) to a string
               NewsTime[Size].EventImportance = EnumToString(event.importance);//storing the event importance from (ENUM_CALENDAR_EVENT_IMPORTANCE) to a string
               NewsTime[Size].EventId = event.id;//storing the event id
               NewsTime[Size].EventDate = TimeToString(values[x].time);//storing normal event time
               NewsTime[Size].EventCurrency = countries[i].currency;//storing event currency
               NewsTime[Size].EventCode = countries[i].code;//storing event code
               NewsTime[Size].EventSector = EnumToString(event.sector);//storing event sector from (ENUM_CALENDAR_EVENT_SECTOR) to a string

               if(values[x].HasForecastValue())//Checks if the event has a forecast value
                 {
                  NewsTime[Size].EventForecast = (string)values[x].forecast_value;//storing the forecast value into a string
                 }
               else
                 {
                  NewsTime[Size].EventForecast = "None";//storing 'None' as the forecast value
                 }

               if(values[x].HasPreviousValue())//Checks if the event has a previous value
                 {
                  NewsTime[Size].EventPreval = (string)values[x].prev_value;//storing the previous value into a string
                 }
               else
                 {
                  NewsTime[Size].EventPreval = "None";//storing 'None' as the previous value
                 }

               NewsTime[Size].EventImpact =  EnumToString(values[x].impact_type);//storing the event impact from (ENUM_CALENDAR_EVENT_IMPACT) to a string
               NewsTime[Size].EventFrequency =  EnumToString(event.frequency);//storing the event frequency from (ENUM_CALENDAR_EVENT_FREQUENCY) to a string
               Size++;//incrementing the Calendar array NewsTime
              }
           }
        }
     }
  }


データを入手したら、次はそれをカレンダーの表に挿入する必要があります。

bool              InsertIntoTable(int db,DST_type Type,Calendar &Evalues[]);//Function for inserting Economic Data in to a database's table

InsertIntoTable関数は、このタスクを実行するのに役立ちます。パラメータは3つあります。

1.この入力パラメータはデータベースの整数値です。

int db

2.この入力パラメータは夏時間スケジュールです。

DST_type Type

3.この配列参照は、前回の関数EconomicDetailsから取得したカレンダーイベントの入力です。

Calendar &Evalues[]

 この関数では、個々のイベントの日付が夏時間スケジュール内にある場合はイベントの日付に1時間加算し、サーバーの現在時刻が夏時間スケジュール内にある場合はイベントの日付から1時間減算します。次に、すべての経済イベントデータをカレンダーの表Data_%sに格納します。

bool CNews::InsertIntoTable(int db,DST_type Type,Calendar &Evalues[])
  {
   string tableName;//will store the table name suffix
   for(uint i=0; i<Evalues.Size(); i++)//Looping through all the Economic Events
     {
      string Date;//Will store the date for the economic event
      switch(Type)//Switch statement to check all possible 'case' scenarios for the variable Type
        {
         case DST_NONE://if(Type==DST_NONE) then run code below
            Date = Evalues[i].EventDate;//Assign the normal Economic EventDate
            tableName = "None";//Full table name will be 'Data_None'
            break;//End switch statement
         case US_DST://if(Type==US_DST) then run code below
            Savings_US.adjustDaylightSavings(StringToTime(Evalues[i].EventDate),Date);//Assign by Reference the Economic EventDate adjusted for US DST(Daylight Savings Time)
            tableName = "US";//Full table name will be 'Data_US'
            break;//End switch statement
         case UK_DST://if(Type==UK_DST) then run code below
            Savings_UK.adjustDaylightSavings(StringToTime(Evalues[i].EventDate),Date);//Assign by Reference the Economic EventDate adjusted for UK DST(Daylight Savings Time)
            tableName = "UK";//Full table name will be 'Data_UK'
            break;//End switch statement
         case AU_DST://if(Type==AU_DST) then run code below
            Savings_AU.adjustDaylightSavings(StringToTime(Evalues[i].EventDate),Date);//Assign by Reference the Economic EventDate adjusted for AU DST(Daylight Savings Time)
            tableName = "AU";//Full table name will be 'Data_AU'
            break;//End switch statement
         default://if(Type==(Unknown value)) then run code below
            Date = Evalues[i].EventDate;//Assign the normal Economic EventDate
            tableName = "None";//Full table name will be 'Data_None'
            break;//End switch statement
        }

      string request_text =
         StringFormat("INSERT INTO 'Data_%s'(ID,EVENTID,COUNTRY,EVENTNAME,EVENTTYPE,EVENTIMPORTANCE,EVENTDATE,EVENTCURRENCY,EVENTCODE,"
                      "EVENTSECTOR,EVENTFORECAST,EVENTPREVALUE,EVENTIMPACT,EVENTFREQUENCY)"
                      "VALUES (%d,%d,'%s','%s', '%s', '%s', '%s','%s','%s','%s','%s','%s','%s','%s')",
                      tableName,
                      i,
                      Evalues[i].EventId,
                      Evalues[i].CountryName,
                      Evalues[i].EventName,
                      Evalues[i].EventType,
                      Evalues[i].EventImportance,
                      Date,
                      Evalues[i].EventCurrency,
                      Evalues[i].EventCode,
                      Evalues[i].EventSector,
                      Evalues[i].EventForecast,
                      Evalues[i].EventPreval,
                      Evalues[i].EventImpact,
                      Evalues[i].EventFrequency);//Inserting all the columns for each event record

      if(!DatabaseExecute(db, request_text))//Checks whether the event was inserted into the table 'Data_%s'
        {
         Print(GetLastError());
         PrintFormat("INSERT INTO 'Data_%s'(ID,EVENTID,COUNTRY,EVENTNAME,EVENTTYPE,EVENTIMPORTANCE,EVENTDATE,EVENTCURRENCY,EVENTCODE,"
                      "EVENTSECTOR,EVENTFORECAST,EVENTPREVALUE,EVENTIMPACT,EVENTFREQUENCY)"
                      "VALUES (%d,%d,'%s','%s', '%s', '%s', '%s','%s','%s','%s','%s','%s','%s','%s')",
                      tableName,
                      i,
                      Evalues[i].EventId,
                      Evalues[i].CountryName,
                      Evalues[i].EventName,
                      Evalues[i].EventType,
                      Evalues[i].EventImportance,
                      Date,
                      Evalues[i].EventCurrency,
                      Evalues[i].EventCode,
                      Evalues[i].EventSector,
                      Evalues[i].EventForecast,
                      Evalues[i].EventPreval,
                      Evalues[i].EventImpact,
                      Evalues[i].EventFrequency);//Will print the sql query to check for any errors or possible defaults in the query/request

         return false;//Will end the loop and return false, as values failed to be inserted into the table
        }
     }
   return true;//Will return true, all values were inserted into the table successfully
  }


表を作成し、そこに経済データを挿入したら、そのアクションがいつ実行されたかのタイムスタンプが必要になります。これは、表を更新するタイミングを知るためです。

void              CreateRecords(int db);//Creates a table to store records of when last the Calendar database was updated/created

Recordsという表を作成し、カレンダー表を作成または更新するたびに、現在のサーバー時刻をこの表に格納します。

void CNews::CreateRecords(int db)
  {
   bool failed=false;

   if(!DatabaseTableExists(db,"Records"))//Checks if the table 'Records' exists in the databse 'Calendar'
     {
      //--- create the table
      if(!DatabaseExecute(db,"CREATE TABLE Records(RECORDEDTIME INT NOT NULL);"))//Will attempt to create the table 'Records'
        {
         Print("DB: create the Records table failed with code ", GetLastError());
         DatabaseClose(db);//Close the database
         return;//Exits the function if creating the table failed
        }
     }

//Sql query/request to insert the current time into the 'RECORDEDTIME' column in the table 'Records'
   string request_text=StringFormat("INSERT INTO 'Records'(RECORDEDTIME) VALUES (%d)",(int)TimeCurrent());

   if(!DatabaseExecute(db, request_text))//Will attempt to run this sql request/query
     {
      Print(GetLastError());
      PrintFormat("INSERT INTO 'Records'(RECORDEDTIME) VALUES (%d)",(int)TimeCurrent());
      failed=true;//assign true if the request failed
     }

   if(failed)
     {
      //--- roll back all transactions and unlock the database
      DatabaseTransactionRollback(db);
      PrintFormat("%s: DatabaseExecute() failed with code %d", __FUNCTION__, GetLastError());
     }
  }

 

これで基本的にすべての関数の準備ができましたが、あと3つだけ注目したい関数があります。最初の関数

bool              UpdateRecords();//Checks if the main Calendar database needs an update or not

この関数は、Recordsと呼ばれる表の最大レコードが現在の日付内にある場合、falseを返します(カレンダー表が現在の日に既に作成または更新されており、今日それ以上の更新をおこなう必要がないことを意味します)。この関数は、カレンダー表が存在しないか、カレンダーデータベースが存在しないか、Recordsと呼ばれる表の最大レコードが現在の日付(日)内にない場合にtrueを返します。

bool CNews::UpdateRecords()
  {
//--- open/create
   int db=DatabaseOpen(NEWS_DATABASE_FILE, DATABASE_OPEN_READONLY|DATABASE_OPEN_COMMON);//try to open database Calendar

   if(db==INVALID_HANDLE)//Checks if the database was able to be opened
     {
      //if opening the database failed
      if(!FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON))//Checks if the database Calendar exists in the common folder
        {
         return true;//Returns true when the database was failed to be opened and the file doesn't exist in the common folder
        }
     }

   if(!DatabaseTableExists(db,"Records"))//If the database table 'Records' doesn't exist
     {
      DatabaseClose(db);
      return true;
     }

   int recordtime=0;//will store the maximum date recorded in the database table 'Records'
   string request_text="SELECT MAX(RECORDEDTIME) FROM Records";//Sql query to determine the lastest or maximum date recorded
   int request=DatabasePrepare(db,request_text);//Creates a handle of a request, which can then be executed using DatabaseRead()
   if(request==INVALID_HANDLE)//Checks if the request failed to be completed
     {
      Print("DB: ",NEWS_DATABASE_FILE, " request failed with code ", GetLastError());
      DatabaseClose(db);
      return true;
     }

   for(int i=0; DatabaseRead(request); i++)//Will read all the results from the sql query/request
     {
      if(!DatabaseColumnInteger(request, 0, recordtime))//Will assign the first column value to the variable 'recordtime'
        {
         Print(i, ": DatabaseRead() failed with code ", GetLastError());
         DatabaseFinalize(request);//Removes a request created in DatabasePrepare()
         DatabaseClose(db);//Closes the database
         return true;
        }
     }

   DatabaseFinalize(request);//Removes a request created in DatabasePrepare()
   DatabaseClose(db);//Closes the database

   if(!Time.DateisToday((datetime)recordtime))//Checks if the recorded time/date is today(current day)
     {
      return true;
     }

   return false;
  }


私が注目したい2番目の関数は

datetime          GetLastestNewsDate();//Gets the lastest/newest date in the Calendar database

です。この関数は前のUpdateRecordsと似ていますが、違いは、GetLastestNewsDateは表Recordsに記録された最大時間を返すだけであり、これは後でユーザーがストラテジー テスターでこの日付より後の日付をテストしようとした場合に通知するために使用されるということです。ユーザーやトレーダーには、この日を過ぎるとテストする経済イベントがないことを伝えます。

datetime CNews::GetLastestNewsDate()
  {
//--- open the database 'Calendar' in the common folder
   int db=DatabaseOpen(NEWS_DATABASE_FILE, DATABASE_OPEN_READONLY|DATABASE_OPEN_COMMON);

   if(db==INVALID_HANDLE)//Checks if 'Calendar' failed to be opened
     {

      if(!FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON))//Checks if 'Calendar' database exists
        {
         return 0;//Will return the earliest date which is 1970.01.01 00:00:00
        }
     }

   string eventtime="1970.01.01 00:00:00";//string variable with the first/earliest possible date in MQL5
//Sql query to determine the lastest or maximum recorded time from which the database was updated.
   string request_text="SELECT MAX(RECORDEDTIME) FROM Records";
   int request=DatabasePrepare(db,request_text);

   if(request==INVALID_HANDLE)
     {

      Print("DB: ",NEWS_DATABASE_FILE, " request failed with code ", GetLastError());
      DatabaseClose(db);
      return true;

     }

   for(int i=0; DatabaseRead(request); i++)//Will read all the results from the sql query/request
     {
      if(!DatabaseColumnText(request, 0,eventtime))//Will assign the first column(column 0) value to the variable 'eventtime'
        {

         Print(i, ": DatabaseRead() failed with code ", GetLastError());
         DatabaseFinalize(request);//Finalize request
         DatabaseClose(db);//Closes the database 'Calendar'
         return 0;//Will end the for loop and will return the earliest date which is 1970.01.01 00:00:00
        }
     }

   DatabaseFinalize(request);
   DatabaseClose(db);//Closes the database 'Calendar'

   return StringToTime(eventtime);//Returns the string eventtime converted to datetime
  }


そして、カレンダーデータベースを作成し、このデータベース内の表を作成し、これらの表に値を挿入するために、前に作成した他のすべての関数を呼び出す関数に移ります。

void              CreateEconomicDatabase();//Creates the Calendar database for a specific Broker

これはEAがチャートに接続されたときに呼び出される関数で、データベースを作成します。

void CNews::CreateEconomicDatabase()
  {
   Print("Please wait...");

   if(FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON))//Check if the database exists
     {
      if(!UpdateRecords())//Check if the database is up to date
        {
         return;//will terminate execution of the rest of the code below
        }
     }
   else
     {
      if(!AutoDetectDST(DSTType))//Check if AutoDetectDST went through all the right procedures
        {
         return;//will terminate execution of the rest of the code below
        }
     }

   if(FileIsExist(NEWS_TEXT_FILE,FILE_COMMON))//Check if the database is open
     {
      return;//will terminate execution of the rest of the code below
     }

   Calendar Evalues[];//Creating a Calendar array variable
   bool failed=false,tableExists=false;
   int file=INVALID_HANDLE;
   datetime lastestdate=D'1970.01.01 00:00:00';
//--- open/create the database 'Calendar'
   int db=DatabaseOpen(NEWS_DATABASE_FILE, DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE| DATABASE_OPEN_COMMON);//will try to open/create in the common folder

   if(db==INVALID_HANDLE)//Checks if the database 'Calendar' failed to open/create
     {
      Print("DB: ",NEWS_DATABASE_FILE, " open failed with code ", GetLastError());
      return;//will terminate execution of the rest of the code below
     }
   else
     {
      file=FileOpen(NEWS_TEXT_FILE,FILE_WRITE|FILE_ANSI|FILE_TXT|FILE_COMMON);//try to create a text file 'NewsDatabaseOpen' in common folder
      if(file==INVALID_HANDLE)
        {
         DatabaseClose(db);//Closes the database 'Calendar' if the News text file failed to be created
         return;//will terminate execution of the rest of the code below
        }
     }

   DatabaseTransactionBegin(db);//Starts transaction execution
   Print("Please wait...");

//-- attempt to create the calendar tables
   if(!CreateTable(db,"None",tableExists)||!CreateTable(db,"US",tableExists)
      ||!CreateTable(db,"UK",tableExists)||!CreateTable(db,"AU",tableExists))
     {
      FileClose(file);//Closing the file 'NewsDatabaseOpen.txt'
      FileDelete(NEWS_TEXT_FILE,FILE_COMMON);//Deleting the file 'NewsDatabaseOpen.txt'
      return;//
     }

   EconomicDetails(Evalues);//Retrieving the data from the Economic Calendar

   if(tableExists)//Checks if there is an existing table within the Calendar Database
     {
      //if there is an existing table we will notify the user that we are updating the table.
      PrintFormat("Updating %s",NEWS_DATABASE_FILE);
     }
   else
     {
      //if there isn't an existing table we will notify the user that we about to create one
      PrintFormat("Creating %s",NEWS_DATABASE_FILE);
     }

//-- attempt to insert economic event data into the calendar tables
   if(!InsertIntoTable(db,DST_NONE,Evalues)||!InsertIntoTable(db,US_DST,Evalues)
      ||!InsertIntoTable(db,UK_DST,Evalues)||!InsertIntoTable(db,AU_DST,Evalues))
     {
      failed=true;//Will assign true if inserting economic vaules failed in any of the Data tables
     }

   if(failed)//Checks if the event/s failed to be recorded/inserted into the database table 'Data_%s'
     {
      //--- roll back all transactions and unlock the database
      DatabaseTransactionRollback(db);
      PrintFormat("%s: DatabaseExecute() failed with code %d", __FUNCTION__, GetLastError());
      FileClose(file);//Close the text file 'NEWS_TEXT_FILE'
      FileDelete(NEWS_TEXT_FILE,FILE_COMMON);//Delete the text file, as we are reverted/rolled-back the database
      ArrayRemove(Evalues,0,WHOLE_ARRAY);//Removes the values in the array

     }
   else//if all the events were recorded or inserted into the tables 'Data_%s'
     {
      if(tableExists)
        {
         //Let the user/trader know that the database was updated
         PrintFormat("%s Updated",NEWS_DATABASE_FILE);
        }
      else
        {
         //Let the user/trader know that the database was created
         PrintFormat("%s Created",NEWS_DATABASE_FILE);
        }

      CreateRecords(db);//Will create the 'Records' table and insert the  current time
      CreateAutoDST(db);//Will create the 'AutoDST' table and insert the broker's DST schedule
      FileClose(file);//Close the text file 'NEWS_TEXT_FILE'
      FileDelete(NEWS_TEXT_FILE,FILE_COMMON);//Delete the text file, as we are about to close the database
      ArrayRemove(Evalues,0,WHOLE_ARRAY);//Removes the values in the array
     }
//--- all transactions have been performed successfully - record changes and unlock the database
   DatabaseTransactionCommit(db);
   DatabaseClose(db);//Close the database
  }



次に、このNewsTradingプロジェクトで作成したすべての異なるクラスとファイルで作成したすべてのコードを実行するEAに移ります。

//+------------------------------------------------------------------+
//|                                                  NewsTrading.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include "News.mqh"
CNews NewsObject;
#include "TimeManagement.mqh"
CTimeManagement CTM;
#include "WorkingWithFolders.mqh"
CFolders Folder();//Calling the class's constructor
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   if(!MQLInfoInteger(MQL_TESTER))//Checks whether the program is in the strategy tester
     {
      //Checks whether the database file exists and whether it has been modified in the current date
      if((!CTM.DateisToday((datetime)FileGetInteger(NEWS_DATABASE_FILE,FILE_MODIFY_DATE,true)))||(!FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON)))
        {
         /*
         In the Do while loop below, the code will check if the terminal is connected to the internet.
         If the the program is stopped the loop will break, if the program is not stopped and the terminal
         is connected to the internet the function CreateEconomicDatabase will be called from the News.mqh header file's
         object called NewsObject and the loop will break once called.
         */
         bool done=false;
         do
           {
            if(IsStopped())
              {
               done=true;
              }

            if(!TerminalInfoInteger(TERMINAL_CONNECTED))
              {
               Print("Waiting for connection...");
               Sleep(500);
               continue;
              }
            else
              {
               Print("Connection Successful!");
               NewsObject.CreateEconomicDatabase();//calling the database create function
               done=true;
              }
           }
         while(!done);
        }
     }
   else
     {
      //Checks whether the database file exists
      if(!FileIsExist(NEWS_DATABASE_FILE,FILE_COMMON))
        {
         Print("Necessary Files Do not Exist!");
         Print("Run Program outside of the Strategy Tester");
         Print("Necessary Files Should be Created First");
         return(INIT_FAILED);
        }
      //Checks whether the lastest database date includes the time and date being tested
      datetime lastestdate = CTM.TimePlusOffset(NewsObject.GetLastestNewsDate(),CTM.DaysS());//Day after the lastest recorded time in the database
      if(lastestdate<TimeCurrent())
        {
         Print("Necessary Files OutDated!");
         Print("Database Dates End at: ",lastestdate);
         Print("Dates after %s will not be available for backtest",lastestdate);
         Print("To Update Files:");
         Print("Run Program outside of the Strategy Tester");
        }
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+

 あとはEAとファイルをコンパイルし、チャートにEAを追加して、コーディングしたものを分析し始めるだけです。

そして最も重要なのは、経済指標カレンダーが何を提供するかを見ることです。

プロジェクトファイル

プロジェクトプログラムファイル




MQL5経済指標カレンダーの詳細

ナビゲーティングウィンドウ


すべてのコンパイルが完了したら、取引端末を開き、ナビゲーターウィンドウを見つけてNewsTradingフォルダを開きます。


EAをチャートに接続

次に、EAを選択したチャートに接続します。ここでは、取引をおこなわないため、[アルゴリズム取引を許可]は有効にしません。[OK]を押して、EAを接続します。



EA出力メッセージ

EAがチャートに接続されると、端末の下部にある[エキスパート]タブにデータベースが正常に作成されたことを知らせるテキストが出力されます。


CommonFolderIDE


取引端末の上部にある[IDE]ボタンを探し、ボタンを押すと、別のウィンドウが開きます。

取引端末IDEの左上にある[ファイル]ボタンを探し、[共通データフォルダを開く]を選択します。


ファイルディレクトリ 

ファイルディレクトリは、上の画像のようになるはずです。[Files]というフォルダにあるファイルが表示されます。


NewsTradingフォルダ

NewsCalendarフォルダ

証券会社フォルダ

NewsTradingフォルダが作成され、その他多くのフォルダが作成されていることがわかります。


ディレクトリ

カレンダーデータベースファイル

すべてのフォルダを開くと、証券会社の分離されたCalendar SQLiteデータベースが見つかります。

MQL5 IDEに戻ります。


フォルダアイコン

IDEの左上にあるフォルダアイコンを選択すると、MetaQoutes Common Folderに移動します。


データベースファイル

次に、証券会社のカレンダーSQLiteデータベースを探し、それを開きます。



データベースを開く

ナビゲータウィンドウにデータベースの内容が表示されているはずなので、最初の表を右クリックして[Open Table]を選択します。



AutoDST表

表が開き、AutoDSTからのすべてのレコード(*)が表示されます。これは証券会社が推奨するDSTカレンダーの表であるため、この表には1つのレコードのみが存在します。


Data_AU表

Data_AU表を開くと、この表のすべてのレコードとすべての列が表示されます。



カレンダー表の結合

SQLクエリ

SELECT  None.EVENTNAME, DATE(REPLACE(None.EVENTDATE,'.','-')) as Date, TIME(REPLACE(None.EVENTDATE,'.','-')) as Time_None,

TIME(REPLACE(US.EVENTDATE,'.','-')) as Time_US, TIME(REPLACE(UK.EVENTDATE,'.','-')) as Time_UK, TIME(REPLACE(AU.EVENTDATE,'.','-')) as Time_AU

FROM 'Data_None' None

INNER JOIN 'Data_US' US on US.ID=None.ID

INNER JOIN 'Data_UK' UK on UK.ID=None.ID

INNER JOIN 'Data_AU' AU on AU.ID=None.ID

WHERE Date BETWEEN '2023-01-01' AND '2024-01-01' AND None.EVENTID='840100001';

目的:このクエリは、2023-01-01から2024-01-01までで、イベントIDが840100001のイベントの名前と、イベント日付をDate、時刻をTime_NoneとしてData_None表から表示するものです。また、表Data_UK、Data_US、Data_AUから同じイベントIDを選択し、これらの表からのイベントの時間をTime_UK、Time_US、Time_AUとして表示します。このクエリでは、2023年通年の同じイベントについて、異なるカレンダー表間の時間差を表示します。

上記のSQLクエリでは、表Data_None、Data_US、Data_UK、Data_AUにそれぞれ、None、US、UK、AUというエイリアスを与えています。

表Data_Noneから

None.EVENTNAME

をSELECTします。


SQL関数では、

REPLACE(None.EVENTDATE,'.','-')

None.EVENTDATEの値のドット文字('.')は、ダッシュ文字('-')に置き換えられます。これは、SQLの

DATE()

関数は、文字区切りとしてダッシュを使用したdatetimeの日付のみを受け入れ、文字区切りとしてドットを使用したdatetimeの日付は受け入れないからです。この関数はdatetimeをdateに変換します。


TIME()

このSQL関数は日時を時間に変換します。



異なる国

SQLクエリ 

SELECT Distinct(COUNTRY) FROM 'Data_None';

目的:このクエリは、カレンダー表Data_Noneにレコードを持つユニークな国すべてを提供します。



結果のエクスポート

SQLクエリの結果を保存し、後で分析したい場合は、結果のいずれかを右クリックし、CSVファイルをエクスポートすることができます。

これにより、分析の効果性が改善されます。 


ニュージーランド

SQLクエリ 

SELECT * FROM 'Data_None' where COUNTRY='New Zealand';

目的:このクエリは、特定の国のすべてのレコードを出力します。この場合、それはニュージーランドです。



ユニークイベントID

SQLクエリ 

SELECT Distinct(EVENTID), COUNTRY, EVENTNAME,EVENTTYPE, EVENTSECTOR, EVENTIMPORTANCE, EVENTFREQUENCY,
EVENTCURRENCY, EVENTCODE FROM 'Data_None' 
where COUNTRY='New Zealand';

目的:このクエリは、特定の国のすべてのユニークなイベントIDを取得し、EVENTNAMEEVENTSECTORなどの特定の列を選択します。

ただし、EVENTIDごとにEVENTDATEが異なるので、具体的にはEVENTDATEではありません。このクエリにEVENTDATEを含めようとするとエラーが返されます。



特定のイベントセクター

SQLクエリ 

SELECT Distinct(EVENTID), COUNTRY, EVENTNAME, EVENTTYPE, EVENTIMPORTANCE FROM 'Data_None' 
where COUNTRY='New Zealand' and EVENTSECTOR='CALENDAR_SECTOR_PRICES';

目的:このクエリは、特定のCOUNTRYとEVENTSECTORのすべてのユニークなイベントIDを取得します。



重要度の高いイベント

SQLクエリ

SELECT COUNTRY,EVENTNAME, EVENTIMPORTANCE FROM 'Data_None' 
where EVENTIMPORTANCE='CALENDAR_IMPORTANCE_HIGH'
UNION
SELECT COUNTRY,EVENTNAME, EVENTIMPORTANCE FROM 'Data_None' 
where EVENTIMPORTANCE='CALENDAR_IMPORTANCE_HIGH';

目的:このクエリは、イベントの重要度が CALENDAR_IMPORTANCE_HIGHのユニークレコードをすべて検索します。



結論

この記事から得られることはたくさんあります。この記事を読んで何か新しいことを学び、新しいアイデアを得ていただければ幸いです。この記事では、データベースを使用することが正しい選択である理由と、データベースを使用するメリットについて説明しました。また、MQL 5の経済指標カレンダーで提供されるすべての通貨と、DST(夏時間)の概念を確認しました。さらに、カレンダーデータベースを作成し、データベースを更新するか作成するかを確認するために、さまざまな必須ファイルをコーディングしました。

最後に、一度作成したデータベースファイルを見つけ、基本的なSQLクエリを使って特定のデータを抽出し、表を操作しました。次の記事では、リスク管理に取り組みます。またお会いしましょう。


MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/14324

添付されたファイル |
知っておくべきMQL5ウィザードのテクニック(第15回):ニュートンの多項式を用いたサポートベクトルマシン 知っておくべきMQL5ウィザードのテクニック(第15回):ニュートンの多項式を用いたサポートベクトルマシン
サポートベクトルマシンは、データの次元を増やす効果を調べることで、あらかじめ定義されたクラスに基づいてデータを分類します。これは教師あり学習法で、多次元のデータを扱う可能性を考えるとかなり複雑です。この記事では、2次元データの非常に基本的な実装であるニュートンの多項式が、価格とアクションを分類する際にどのように効率的に実行できるかを検討します。
GMDH (The Group Method of Data Handling):MQL5で多層反復アルゴリズムを実装する GMDH (The Group Method of Data Handling):MQL5で多層反復アルゴリズムを実装する
この記事では、MQL5におけるGMDH (The Group Method of Data Handling)の多層反復アルゴリズム実装について説明します。
フェアバリューギャップ(FVG)/不均衡取引方法をステップバイステップで学ぶ:スマートマネーコンセプトのアプローチ フェアバリューギャップ(FVG)/不均衡取引方法をステップバイステップで学ぶ:スマートマネーコンセプトのアプローチ
フェアバリューギャップ(FVG)取引戦略に基づいて、MQL5で自動売買アルゴリズムを作成して実装するためのステップバイステップのガイドです。初心者にも経験豊富なトレーダーにも役立つエキスパートアドバイザー(EA)の作成に関する詳細なチュートリアルです。
どんな市場でも優位性を得る方法 どんな市場でも優位性を得る方法
現在の技術レベルに関係なく、取引したいどのような市場でも先んじることができる方法を学びましょう。