前回はトレードタイマークラスに実装するメンバ関数の第2弾として、「毎日同じ時間帯に取引できるようにする関数」=DailySessionTimer関数を実装する様子を解説しました。
まず最初に、FXにおける各オープン市場の特徴を簡単に紹介した上で、毎日同じ時間帯に取引できるようにシステム的に管理できる事の意義を説明しました。詳しくは前回記事の
「はじめに:毎日同じ時間帯に取引できるようにする関数について」セクションをご確認ください。
そして、ロードマップに示した手順に従い、CTradeSessionクラスにDailySessionTimer関数を始めとしたいくつかのメンバを追加し、
仮引数設定~処理実装記述までを解説していきました。
詳しくは前回記事の下記セクションをご確認ください↓
・「CTradeSession」クラス内に新しいメンバを加える
・メンバ関数「DailySessionTimer」に必要な仮引数を設定する
・メンバ関数「DailySessionTimer」に処理実装記述をおこなう
はじめに:「トレード時間のオンオフをわかりやすく表示する関数」とは?
今回も引き続きトレードタイマークラスについてです。
今回はCTradeSessionクラスに、「トレード時間のオンオフをわかりやすく表示する関数」を追加していきます。
前回作った、「毎日同じ時間帯に取引できるようにする関数」=DailySessionTimer関数には、そのままだと若干物足りない部分があります。
それは今、トレード時間がオンなのかオフなのか、というのが分かり辛いという点です。
一応DailySessionTimer関数の処理中にPrint関数でトレードタイマーがオンになっているのか、オフになっているのかをエキスパートログに出力するようにはしているのですが、あくまでbool型のtrueかfalseの戻り値を表示させるだけの簡易なものです。
なによりMT5のエキスパートログタブを一々開いて確認しなくてはならないというのも面倒です。
そこで、今回追加する「トレード時間のオンオフをわかりやすく表示する関数」をメンバとしてクラスに追加する事によって、DailySessionTimer関数が処理したトレードオンオフの切り替え状況をMT5のチャート上にももっとわかりやすく表示しよう!というのが今回やろうとしている事です。
「トレード時間のオンオフをわかりやすく表示する関数」実装へのロードマップ
「トレード時間のオンオフをわかりやすく表示する関数」実装は以下の手順を踏んで実装していきます。
・「CTradeSession」クラス内に新しいメンバを加える
・DisplayTimerStatus関数に必要な仮引数を設定する
・DisplayTimerStatus関数に処理実装記述をおこなう
順を追って1つ1つ見ていきましょう。
「CTradeSession」クラス内に新しいメンバを加える
今回も「CTradeSession」クラスに新しいメンバを追加します。
前回までの「CTradeSession」クラスのメンバは以下のようになっていました↓
class CTradeSession
{
private:
//トレード開始時間と終了時間を格納する
datetime SessionStartTime, SessionEndTime;
public:
// 取引セッションがアクティブかどうかをチェックする関数
bool IsActive(datetime openTime, datetime closeTime, bool useLocalTime = false);
//毎日のトレードタイマーを作成する関数
bool DailySessionTimer(int parStartHour, int parStartMinute, int parEndHour, int parEndMinute, bool parLocalTime = false);
};
ここから今回さらにメンバを追加して以下のような形に変わります↓
class CTradeSession
{
private:
//トレード開始時間と終了時間を格納する
datetime SessionStartTime, SessionEndTime;
//トレードタイマーのオンオフ状態を格納
bool timerStartedFlag ;
//トレードタイマーのオンオフ状態をチャートとエキスパートログに表示する関数
void DisplayTimerStatus(bool parTimerState);
public:
// 取引セッションがアクティブかどうかをチェックする関数
bool IsActive(datetime openTime, datetime closeTime, bool useLocalTime = false);
//毎日のトレードタイマーを作成する関数
bool DailySessionTimer(int parStartHour, int parStartMinute, int parEndHour, int parEndMinute, bool parLocalTime = false);
};
アクセスレベル=privateの領域に、bool型の変数「timerStartedFlag」、そしてvoid型の関数「DisplayTimerStatus」を追加しました。
※private,protected,publicなどクラスのアクセスレベルについては↓
・MQL5 EA講座 第50回「クラスについて3 -アクセス指定子-」
をご覧ください。
メンバ「timerStartedFlag」について
privateの領域に加えた、bool型の変数「timerStartedFlag」ですが、この変数はこの後解説するDisplayTimerStatus関数の中で使われます。
前回作ったDailySessionTimer関数の戻り値がtrueになったら、それを追うようにtrueに、
反対に戻り値がfalseだったら追従してfalseになるように使います。
メンバ「DisplayTimerStatus関数」について
同じくprivate領域に追加したメンバ関数「DisplayTimerStatus関数」についてですが、戻り値はvoid型です。
この後の処理実装記述を見ればわかりますが、チャート上のコメント表示とエキスパートログ出力を担う関数なので、特に戻り値を必要としません。
DisplayTimerStatus関数に必要な仮引数を設定する
続いてDisplayTimerStatus関数に仮引数を設定していきます。
DisplayTimerStatus関数に設定する仮引数は1つだけです。
仮引数「parTimerState」にはトレード時間中なのか、それともトレード時間外なのかの状態が格納される想定
唯一の仮引数「parTimerState 」には、『トレード時間中なのか、それともトレード時間外なのかの状態』が格納される想定です。
Void CTradeSession::DisplayTimerStatus(bool parTimerState)
DisplayTimerStatus関数はprivate領域のメンバ関数なので、クラスのメンバ以外からはアクセスできません。
従って、これまでの講座記事でもしばしば行っていたような、メインプログラムのinput変数を使うような事はできません。
仮引数「parTimerState」にはクラス内のローカル変数が記述される事になります。
具体的に仮引数「parTimerState」にどのような記述がされるのか?についてはこの後解説します。
DisplayTimerStatus関数に処理実装記述をおこなう
仮引数の設定が終わったので、今度は処理実装記述をほどこしていきます。
DisplayTimerStatus関数の全体記述は以下のようになっています。
void CTradeSession::DisplayTimerStatus(bool parTimerState)
{
// parTimerStateがtrueで、かつtimerStartedFlagがfalseの場合、タイマーが開始されたことを示す。
if(parTimerState == true && timerStartedFlag == false)
{
string message = "タイマー開始"; // "タイマー開始"を代入
Print(message); // メッセージをエキスパートログに出力
Comment(message); // メッセージをチャートに表示
timerStartedFlag = true; // timerStartedFlagをtrueに設定して、タイマーが開始されたことを記録
}
else if(parTimerState == false && timerStartedFlag == true) // parTimerStateがfalseで、かつtimerStartedFlagがtrueの場合、タイマーが停止したことを示す。
{
string message = "タイマー停止"; // "タイマー停止"を代入
Print(message); // メッセージをエキスパートログに出力
Comment(message); // メッセージをチャートに表示
timerStartedFlag = false; // timerStartedFlagをfalseに設定して、タイマーが停止されたことを記録
}
}
上から順番に見ていきましょう
処理実装記述1:トレード時間が始まった時の条件を記述する
// parTimerStateがtrueで、かつtimerStartedFlagがfalseの場合、タイマーが開始されたことを示す。
if(parTimerState == true && timerStartedFlag == false)
{
string message = "タイマー開始"; // "タイマー開始"を代入
Print(message); // メッセージをエキスパートログに出力
Comment(message); // メッセージをチャートに表示
timerStartedFlag = true; // timerStartedFlagをtrueに設定して、タイマーが開始されたことを記録
}
冒頭にはトレード時間が始まった時の条件が記述されています。
if(parTimerState == true && timerStartedFlag == false)
という記述は
「parTimerStateがtrueで、かつtimerStartedFlagがfalseの場合、タイマーが開始されたことを示す」
と読み解けます。
※&&論理積についての詳細は↓の記事をご参照ください
仮引数である「parTimerState」には、前回作ったDailySessionTimer関数の戻り値が格納されるようになっています。
「timerStartedFlag」は今回追加したアクセスレベル=privateの変数です。
「メンバ「timerStartedFlag」について」セクションで説明したように、
DailySessionTimer関数の戻り値がtrueになったら、それを追うようにtrueに、
反対に戻り値がfalseだったら追従してfalseになるように真偽値を格納します。
parTimerState == trueの条件を満たしていて、なおかつ、timerStartedFlag== falseを満たしている時というのは、トレード終了時間からトレード開始時間に切り替わった事を意味します。
従って、{}内の処理でstring型のローカル変数「message」に”タイマー開始”の文字列を代入させています。
「message」に格納された値を、Print関数でエキスパートログに出力し、Comment関数でチャート上に表示します。
そして、最後にメンバ「timerStartedFlag」の値をtrueに切り替え、トレード開始時間中である、という状態を保存します。
※Comment関数についての詳細は↓の記事をご参照ください
処理実装記述2:トレード時間が終了した時の条件を記述する
// parTimerStateがfalseで、かつtimerStartedFlagがtrueの場合、タイマーが停止したことを示す。
else if(parTimerState == false && timerStartedFlag == true)
{
string message = "タイマー停止"; // "タイマー停止"を代入
Print(message); // メッセージをエキスパートログに出力
Comment(message); // メッセージをチャートに表示
timerStartedFlag = false; // timerStartedFlagをfalseに設定して、タイマーが停止されたことを記録
}
トレード開始時間に関する記述が終わったので、今度はトレード終了時間になった時の記述です。
else if(parTimerState == false && timerStartedFlag == true)
という記述は
「parTimerStateがfalseで、かつtimerStartedFlagがtrueの場合、タイマーが停止したことを示す」
と読み解けます。
parTimerState == falseの条件を満たしていて、なおかつ、timerStartedFlag== trueを満たしている時というのは、トレードを許可している時間からトレード終了時間に切り替わった事を意味します。
よって、{}内の処理でstring型のローカル変数「message」に”タイマー停止”の文字列を代入させています。
ここでも同様に、「message」に格納された値を、Print関数でエキスパートログに出力し、Comment関数でチャート上に表示します。
そして、最後にメンバ「timerStartedFlag」の値をfalseに切り替え、トレード終了時間になった、という状態を保存します。
DisplayTimerStatus関数は戻り値がないvoid型なので、処理実装記述はこれで終了です。
DailySessionTimer関数の処理実装記述を変更する
トレード開始時間/終了時間をチャート上に表示するDisplayTimerStatus関数が完成したので、前回作ったDailySessionTimer関数の処理実装記述を変更します。
と言っても変更するのは最後の所だけです。
現在DailySessionTimer関数の記述は以下のようになっているのですが・・・
// セッションがアクティブかどうかを判断
bool timerOn = IsActive(SessionStartTime, SessionEndTime, parLocalTime);
// タイマーの状態を出力
Print(timerOn);
// タイマーがオンかオフかの状態を返す
return(timerOn);
}
Print関数が使われている部分を、DisplayTimerStatus関数に切り替えます↓
// セッションがアクティブかどうかを判断
bool timerOn = IsActive(SessionStartTime, SessionEndTime, parLocalTime);
// タイマーの状態を出力
DisplayTimerStatus(timerOn);
// タイマーがオンかオフかの状態を返す
return(timerOn);
}
ローカル変数「timerOn」は「トレード時間かどうかをチェックする」メンバ関数 」であるIsActive関数の戻り値を受け取っているので、それをDisplayTimerStatus関数の引数として使います。
これで、DailySessionTimer関数をメインプログラムで使用した際に、チャート上にも現在時刻が、設定したトレード時間中なのか、トレード時間外なのかが表示されるようになりました。
まとめ
今回はトレードタイマークラスに実装するメンバ関数の第3弾として「トレード時間のオンオフをわかりやすく表示する関数」= DisplayTimerStatus関数を実装する様子を解説しました。
DisplayTimerStatus関数を実装する意味は、前回作ったDailySessionTimer関数に改良を施すためです。DailySessionTimer関数で設定したトレード開始時間/トレード終了時間を、エキスパートログだけでなく、MT5のチャート上にも表示し表示文言もよりわかりやすくしました。
今回も記事冒頭に示したロードマップに従い、CTradeSessionクラスのprivate領域に2つのメンバを追加し、そのうちの1つであるDisplayTimerStatus関数について、仮引数設定~処理実装記述までを解説しました。
※詳しくは当記事の下記セクションをご覧ください。
・DisplayTimerStatus関数に必要な仮引数を設定する
・DisplayTimerStatus関数に処理実装記述をおこなう
そして、完成したDisplayTimerStatus関数を早速、前回作った「毎日同じ時間帯に取引できるようにする関数」=DailySessionTimer関数にも実装し、トレード開始時間/終了時間がMT5チャート上からも確認できるように改良しました。
※詳しくは当記事の↓
・「DailySessionTimer関数の処理実装記述を変更する」セクションをご覧ください。
現時点での「OriginalTimer.mqh」ファイルに記述した内容は以下の通りです↓
//+------------------------------------------------------------------+
//| OriginalTimer.mqh |
//| |
//| |
//+------------------------------------------------------------------+
#define MINUTES_TO_SECONDS 60 // 1分を秒に変換する定数(60秒)
#define HOURS_TO_SECONDS 3600 // 1時間を秒に変換する定数(3600秒)
#define DAYS_TO_SECONDS 86400 // 1日を秒に変換する定数(86400秒)
#define WEEKS_TO_SECONDS 604800 // 1週間を秒に変換する定数(604800秒)
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class OriginalCNewBar
{
private:
datetime TimeArray[], //現在の時間を格納
LastTimeVar;//直近にチェックした時間
public:
void OriginalCNewBar();//配列「TimeArray」に時系列セットを施すコンストラクタ
//新しいバーがオープンした瞬間かどうかをチェックする
bool CheckNewBar(string parSymbol, ENUM_TIMEFRAMES parTimeframe);
};
//+------------------------------------------------------------------+
//コンストラクタOriginalCNewBarの処理実装記述
void OriginalCNewBar::OriginalCNewBar(void)
{
ArraySetAsSeries(TimeArray,true);//配列「TimeArray」を時系列にセットする
}
// 新しいバーがオープンしたかどうかをチェックするメンバ関数の実装
bool OriginalCNewBar::CheckNewBar(string parSymbol, ENUM_TIMEFRAMES parTimeframe)
{
// 初回実行かどうかを判定するフラグ
bool firstExe = false;
// 新しいバーがオープンしたかどうかを示すフラグ
bool newBarOpen = false;
// 指定されたシンボルと時間枠の現在と一つ前のバーの時間をTimeArrayにコピー
CopyTime(parSymbol, parTimeframe, 0, 2, TimeArray);
// LastTimeVarが0の場合、これが初回実行と判断
if(LastTimeVar == 0)
firstExe = true;
// TimeArrayの最新の時間がLastTimeVarより大きい場合、新しいバーと判断
if(TimeArray[0] > LastTimeVar)
{
// 初回実行ではない場合、newBarフラグをtrueに設定
if(firstExe == false)
newBarOpen = true;
// 最後にチェックしたバーのオープン時間を更新
LastTimeVar = TimeArray[0];
}
// 新しいバーの有無を返す
return(newBarOpen);
}
// 日付時間値を生成する関数
datetime GenerateTimestamp(int newHour = 0, int newMinute = 0)
{
MqlDateTime dateTimeDetails; // MqlDateTime構造体を使用して日時データを保存するための変数
TimeToStruct(TimeCurrent(), dateTimeDetails); // 現在のサーバーの時間を取得し、dateTimeDetails構造体に代入
dateTimeDetails.hour = newHour; // 時間を新しい値に設定
dateTimeDetails.min = newMinute; // 分を新しい値に設定
datetime constructedTime = StructToTime(dateTimeDetails); // MqlDateTime構造体値をdatetime値に変換
return(constructedTime); // 変換したdatetime値を返す
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CTradeSession
{
private:
//トレード開始時間と終了時間を格納する
datetime SessionStartTime, SessionEndTime;
//トレードタイマーのオンオフ状態を格納
bool timerStartedFlag ;
//トレードタイマーのオンオフ状態をチャートとエキスパートログに表示する関数
void DisplayTimerStatus(bool parTimerState);
public:
// 取引セッションがアクティブかどうかをチェックする関数
bool IsActive(datetime openTime, datetime closeTime, bool useLocalTime = false);
//毎日のトレードタイマーを作成する関数
bool DailySessionTimer(int parStartHour, int parStartMinute, int parEndHour, int parEndMinute, bool parLocalTime = false);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CTradeSession::DisplayTimerStatus(bool parTimerState)
{
// parTimerStateがtrueで、かつtimerStartedFlagがfalseの場合、タイマーが開始されたことを示す。
if(parTimerState == true && timerStartedFlag == false)
{
string message = "タイマー開始"; // "タイマー開始"を代入
Print(message); // メッセージをエキスパートログに出力
Comment(message); // メッセージをチャートに表示
timerStartedFlag = true; // timerStartedFlagをtrueに設定して、タイマーが開始されたことを記録
}
else if(parTimerState == false && timerStartedFlag == true) // parTimerStateがfalseで、かつtimerStartedFlagがtrueの場合、タイマーが停止したことを示す。
{
string message = "タイマー停止"; // "タイマー停止"を代入
Print(message); // メッセージをエキスパートログに出力
Comment(message); // メッセージをチャートに表示
timerStartedFlag = false; // timerStartedFlagをfalseに設定して、タイマーが停止されたことを記録
}
}
// 取引セッションがアクティブかどうかをチェックする関数の実装
bool CTradeSession::IsActive(datetime openTime, datetime closeTime, bool useLocalTime = false)
{
// 開始時間が終了時間より後であるかどうかを確認
if(openTime >= closeTime)
{
// 開始時間と終了時間が不正である場合、警告メッセージを出力して処理を中止
Alert("エラー:開始時間または終了時間が不正です");
return false; // 不正な時間設定のため、falseを返す
}
// 現在時刻を取得する
datetime currentTime;
//ローカル時間を使うかどうかのチェック
if(useLocalTime == true)
currentTime = TimeLocal();
else
currentTime = TimeCurrent();
// 現在時刻が開始時間と終了時間の範囲内かどうかをチェック
bool timerOn = false; // タイマーがオンかどうかのフラグを初期化
if(currentTime >= openTime && currentTime < closeTime)
{
// 現在時刻が指定された時間範囲内にある場合、タイマーをオンにする
timerOn = true;
}
return timerOn; // タイマーの状態を返す
}
// Daily timer
bool CTradeSession::DailySessionTimer(int parStartHour, int parStartMinute, int parEndHour, int parEndMinute, bool parLocalTime=false)
{
// 現在の時間を取得
datetime currentTime;
if(parLocalTime == true)
currentTime = TimeLocal(); // ローカル時間を使用
else
currentTime = TimeCurrent(); // サーバー時間を使用
// セッションの開始時間を設定
SessionStartTime = GenerateTimestamp(parStartHour,parStartMinute);
// セッションの終了時間を設定
SessionEndTime = GenerateTimestamp(parEndHour,parEndMinute);
// セッションの終了時間が開始時間より前に設定されている場合、終了時間を調整する
if(SessionEndTime <= SessionStartTime)
{
SessionStartTime -= DAYS_TO_SECONDS; // 開始時間を1日分マイナスする
// 現在時刻が終了時間を過ぎていた場合、開始時間と終了時間を次の日にずらす
if(currentTime > SessionEndTime)
{
SessionStartTime += DAYS_TO_SECONDS;
SessionEndTime += DAYS_TO_SECONDS;
}
}
// セッションがアクティブかどうかを判断
bool timerOn = IsActive(SessionStartTime, SessionEndTime, parLocalTime);
// タイマーの状態を出力
DisplayTimerStatus(timerOn);
// タイマーがオンかオフかの状態を返す
return(timerOn);
}
//+------------------------------------------------------------------+
今回は以上とさせて頂きます。
最後までお読みいただきありがとうございました。
MQL5 EA講座 第120回「トレードタイマークラスを実装する-その2-」←
→MQL5 EA講座 第122回「トレードタイマークラスを実装する-その4-」
<参照>
TimeCurrent関数/TimeToString関数/UNIXタイム/タイムスタンプ/datetime型/iTime関数/StringToTime関数/ENUM_TIMEFRAMES/TimeToStruct関数/GetTickCount関数/MqlDateTime構造体/タイムゾーン/TimeDaylightSavings関数/TimeGMT関数/TimeGMTOffset関数/TimeLocal関数/夏時間/ENUM_DAY_OF_WEEK