この記事ではMQL4、およびMQL5で祝日を考慮したゴトー日(ごとうび)を判定するソースコードを公開します。
祝日の取得と判定については以下の記事をご覧ください。
ゴトー日の条件
- 土日や祝日はゴトー日には該当しない
- 5、10、15、20、25日
- 月末日
- ゴトー日が祝日や土日に当たる場合、その前の営業日
WAN
人間では容易にわかることでも、プログラミングでは難関よね(‘Д’)
MQL4&MQL5 兼用について
MQL4とMQL5、どちらでも動くようにしています。
特にTimeDay、TimeDayOfWeek、TimeMonth、TimeYearは、MQL4の標準関数ですので、「条件付きコンパイル」を使用してMQL5でコンパイルされた場合は、それらの関数を定義するようにしています。
MQL5のドキュメンテーション: 言語基礎 / プリプロセッサ / 条件付きコンパイル( #ifdef、#ifndef、#else、#endif )
条件付きコンパイル( #ifdef、#ifndef、#else、#endif ) - プリプロセッサ - 言語基礎 - MQL5 リファレンス - MetaTrader 5 のためのアルゴリズムの/自動化されたトレーディング言語のリファレン...
ソースコード
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//祝日の読み込み
HolidayRead();
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//ゴトー日の判定
bool isGoto = GotobiFilterLogic(D'2024.8.30');
if(isGoto)
Print("ゴトービです");
else
Print("ゴトービではありません");
}
//+------------------------------------------------------------------+
//| ゴトー日判定関数 引数:該当の日本時刻 ワンダフルFXライフ
//+------------------------------------------------------------------+
bool GotobiFilterLogic(datetime search_time)
{
int search_day = TimeDay(search_time);
int search_week = TimeDayOfWeek(search_time);
int search_month = TimeMonth(search_time);
int search_year = TimeYear(search_time);
// 土日または祝日であればfalse
if(search_week == SUNDAY || search_week == SATURDAY || HolidayFilterLogic(search_time))
return(false);
// 5, 10, 15, 20, 25日のいずれかであればtrue
if(search_day == 5 || search_day == 10 || search_day == 15 || search_day == 20 || search_day == 25)
return(true);
// 月末日を計算
datetime first_day_next_month = (search_month == 12) ?
StringToTime((string)(search_year + 1) + ".01.01 00:00") :
StringToTime((string)search_year + "." + (string)(search_month + 1) + ".01 00:00");
datetime last_day_this_month = first_day_next_month - 60 * 60 * 24;
// 月末日であればtrue
if(search_time >= last_day_this_month && search_time < first_day_next_month)
return(true);
// 次のゴトービを計算
int next_gotobi_day = (search_day <= 25) ? search_day + (5 - (search_day % 5)) : TimeDay(last_day_this_month);
datetime next_gotobi_time = StringToTime((string)search_year + "." + (string)search_month + "." + (string)next_gotobi_day);
// 次のゴトービが土日祝日であればその前の営業日を探す
while(TimeDayOfWeek(next_gotobi_time) == SUNDAY || TimeDayOfWeek(next_gotobi_time) == SATURDAY || HolidayFilterLogic(next_gotobi_time))
{
next_gotobi_time -= 60 * 60 * 24; // 1日戻る
}
return(search_time == next_gotobi_time);
}
#ifdef __MQL5__ //ここから#endifまでMT5のときのみ有効にする
//+------------------------------------------------------------------+
//| MT5のみ 引数で受け取った時刻の日を返す関数 ワンダフルFXライフ
//+------------------------------------------------------------------+
int TimeDay(datetime date)
{
MqlDateTime tm;
TimeToStruct(date, tm);
return(tm.day);
}
//+------------------------------------------------------------------+
//| MT5のみ 引数で受け取った時刻の曜日を返す関数 ワンダフルFXライフ
//+------------------------------------------------------------------+
int TimeDayOfWeek(datetime date)
{
MqlDateTime tm;
TimeToStruct(date, tm);
return(tm.day_of_week);
}
//+------------------------------------------------------------------+
//| MT5のみ 引数で受け取った時刻の月を返す関数 ワンダフルFXライフ
//+------------------------------------------------------------------+
int TimeMonth(datetime date)
{
MqlDateTime tm;
TimeToStruct(date, tm);
return(tm.mon);
}
//+------------------------------------------------------------------+
//| MT5のみ 引数で受け取った時刻の年を返す関数 ワンダフルFXライフ
//+------------------------------------------------------------------+
int TimeYear(datetime date)
{
MqlDateTime tm;
TimeToStruct(date, tm);
return(tm.year);
}
#endif
//+------------------------------------------------------------------+
//| 引数で受け取った時刻が祝日かどうかを返す関数 ワンダフルFXライフ
//+------------------------------------------------------------------+
bool HolidayFilterLogic(datetime search_time)
{
//始値に修正
search_time = StringToTime(TimeToString(search_time, TIME_DATE));
int csv_size = ArrayRange(HolidayArray, 0);
for(int i = 0; i < csv_size; i++)
{
datetime csvtime = StringToTime(HolidayArray[i][0]);//祝日配列の日付部分
if(csvtime == search_time)
return(true);
}
return(false);
}
//+------------------------------------------------------------------+
//| Webページを読み込んでstringに代入する関数 ワンダフルFXライフ
//+------------------------------------------------------------------+
#import "wininet.dll"
int InternetOpenW(string agent, int accessType, string proxyName, string proxyByPass, int flags);
int InternetOpenUrlW(int internetSession, string url, string headers, int headersLength, int flags, int context);
int InternetReadFile(int handle, uchar &buffer[], int numberOfBytesToRead, int &numberOfBytesRead);
int InternetCloseHandle(int handle);
#import
string ReadWebPage(string url)
{
string text = "";
if(TerminalInfoInteger(TERMINAL_DLLS_ALLOWED) == false)
{
Comment("DLLの使用を許可してください");
return(text);
}
int inet = InternetOpenW("MetaTrader 5 Terminal", 0, NULL, NULL, 0);
if(inet == 0)
{
Comment("InternetOpenW failed.");
return(text);
}
int handle = InternetOpenUrlW(inet, url, NULL, 0, 0, 0);
if(handle == 0)
{
Comment("InternetOpenUrlW failed.");
InternetCloseHandle(inet);
return(text);
}
int byteSize = 0;
uchar receive[1024];//1キロバイトずつが最適
while(InternetReadFile(handle, receive, ArraySize(receive), byteSize))
{
if(byteSize <= 0)
break;
text += CharArrayToString(receive, 0, byteSize);
}
InternetCloseHandle(handle);
InternetCloseHandle(inet);
return(text);
}
//+------------------------------------------------------------------+
//| 国民の祝日CSVを読み込んで配列に格納する関数 ワンダフルFXライフ
//+------------------------------------------------------------------+
string HolidayArray[][2];//日付、名称
const string HolidayURL = "https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv";
void HolidayRead()
{
string holiday_txt = ReadWebPage(HolidayURL);
string result[];
int rows = StringSplit(holiday_txt, '\n', result);
ArrayResize(HolidayArray, rows - 1); // ヘッダー行を除く行数で配列をリサイズ
for(int i = 1; i < rows; i++)
{
string columns[];
StringSplit(result[i], ',', columns); // カンマで列を分割
if(ArraySize(columns) >= 2)
{
string holiday = columns[0];
StringReplace(holiday, "/", "."); // 日付のフォーマットを変更
HolidayArray[i - 1][0] = holiday; // 日付
HolidayArray[i - 1][1] = columns[1]; // 名称
}
}
}
//+------------------------------------------------------------------+
ソースコードでは2024/8/30を関数に渡していますが、日本時間を計算して渡すようにしてください。
日本時間の計算方法についてはまた別記事で行いたいと考えてます。
まとめ
じゃんじゃん使ってくださいね(‘ω’)