はじめに:OnTimer関数について
ここしばらくは、ずっと時間情報を管理・操作をする為の講座内容が続いていました↓
- MQL5 EA講座 第115回「チャート上に新しいバーが生成される瞬間にのみ注文できるクラスを作る」
- MQL5 EA講座 第116回「DateTime型を使って、日時データを操作する時の基本的な考え方」
- MQL5 EA講座 第117回「MqlDateTime構造体について」
- MQL5 EA講座 第118回「特定の日時を簡単に生成できる関数を実装する」
- MQL5 EA講座 第119回「トレードタイマークラスを実装する-その1-」
- MQL5 EA講座 第120回「トレードタイマークラスを実装する-その2-」
- MQL5 EA講座 第121回「トレードタイマークラスを実装する-その3-」
- MQL5 EA講座 第122回「トレードタイマークラスを実装する-その4-」
- MQL5 EA講座 第123回「トレードタイマークラスを実装する-その5-」
時間情報の管理・操作については、突き詰めていけばそれこそ無限に掘り下げていける奥深い領域ではありますが、いつまでも続けている訳にはいかないので一旦この辺にしておきましょう。
が!最後の最後に、時間情報の管理・操作に関連するイベントハンドラーであるOnTimer関数という関数について触れてからにしたいと思います。
改めて復習:イベントハンドラーとは?
OnTimer関数について触れる前に、改めてここで一度「そもそもイベントハンドラーとは何か?」という部分をおさらいしておきましょう(この講座もだいぶ長丁場になってきましたからね・・・)
event=出来事 handler=処理・扱うもの
すなわち、特定の出来事が起こるたびに実行される関数のことを指します。
今までに取り上げてきた中だと、OnTick関数やOnStart関数、OnInit関数、OnDeinit関数などがイベントハンドラーにあたります。
<参照>
OnTick関数であれば値動きの変化をイベントと捉え、その度に処理が実行されますし、
OnInit関数であればMT5のチャートにプログラムファイルが挿入された事をイベントとして捉え、それをきっかけに処理を実行する・・・といった具合です。
そしてこれまでの講座記事では基本的にOnTick関数とOnInit関数しか使っていませんでした。
EAというのは、自動売買プログラムな訳ですから、価格の変動に対するアクションに反応するよう設計されることは自然な事ですし、今後も主要な記述はOnTick関数の{}内に記述していく事に変わりはないでしょう。
その一方で、OnTick関数は言い換えれば「価格の変動がなければ処理を実行しない」とも言えますから、価格の変動を待たずに実行させたい処理がある場合は、別のイベントハンドラーを用いる必要があります。
今回解説するOnTimer関数もその1つです。
OnTimer関数の役割・働き
OnTick関数が、価格変動が受信されたときにのみ実行されるのに対し、
OnTimer関数は、任意に指定する「X秒」ごとに実行することができる関数(=イベントハンドラー)となっています。(秒数の指定方法は後程説明します)
取引戦略を「価格変動」に依存せず、定期的な間隔でアクションを実行させたい場合は、そのコードを OnTimer関数の{}内に記述すればよい、という事になります。
OnTimer関数の引数と戻り値について
void OnTimer(void);
上記のOnTimer関数に関する定義を見てもらえばわかる通り、OnTimer関数は引数を取りません。
したがって、特定のパラメーターを入力せずに{}内に指定間隔ごとに実行してほしい処理を記述していけば大丈夫です。
またOnTimer関数は戻り値も持たないvoid型です。直接的な出力値を生成せず、{}内に記述された処理のみをおこないます。
OnTimer関数を使ったサンプルコードを作成するためのロードマップ
これからOnTimer関数の使い方を理解するためのサンプルコードを作っていきます。
サンプルコードの全体は以下のようになっています。
// OnInit関数でタイマーを1秒間隔で設定します
int OnInit() {
Comment(""); // コメントをクリア
EventSetTimer(1); // 1秒ごとにタイマーイベントを生成
return(INIT_SUCCEEDED);
}
// OnTimer関数でタイマーイベントが発生するたびに呼ばれます
void OnTimer() {
datetime serverTime = TimeCurrent(); // サーバーの現在時刻を取得
// サーバー時刻をコンソールに出力
Print("サーバーの現在時刻: ", TimeToString(serverTime, TIME_DATE|TIME_MINUTES));
}
// ファイルがチャートから削除される時に実行される関数
void OnDeinit(const int reason) {
EventKillTimer(); // タイマーを停止します
// チャートから削除されたことをユーザーに通知
if (reason == REASON_REMOVE) {
Comment("このエキスパートアドバイザーはチャートから削除されました。");
}
}
上記のコードは以下のような手順を踏んで記述していきます。
・手順1:OnInit関数内にEventSetTimer関数を記述し、タイマーイベントを設定する。
・手順3:OnDeinit関数内にEventKillTimer関数を記述し、タイマーイベント削除設定をする。
順を追って見ていきましょう
手順1:OnInit関数内にEventSetTimer関数を記述し、タイマーイベントを設定する。
// OnInit関数でタイマーを1秒間隔で設定します
int OnInit() {
Comment(""); // コメントをクリア
EventSetTimer(1); // 1秒ごとにタイマーイベントを生成
return(INIT_SUCCEEDED);
}
OnTimer関数はそれ単体で使えるものではありません。「どのくらいの間隔で処理を実行するか」という設定をOnInit関数内でおこないます。
OnInit関数内は、プログラムの初期化段階で実行されるため、設定に関連する記述を行うにはもっとも都合が良いイベントハンドラーになります。
冒頭の、
Comment(“”);
はComment関数に空の文字列を引数に記述しています。このような記述を行うと、チャートに以前のコメントが残っていた場合にそのコメントを消去してくれます。
「どのくらいの間隔で処理を実行するか」という設定はEventSetTimer関数という関数を使います。
EventSetTimer関数は引数に、定期実行したい間隔を「秒」単位で指定します。今回は1秒ごとに処理を行いたいので引数に「1」と記述しました。
EventSetTimer(1);
※EventSetTimer関数についての詳細は↓の記事をご参照ください
なお、今回はタイマー設定としてEventSetTimer関数を使いましたが、EventSetMillisecondTimer関数というミリ秒(=1/1000秒)というもっと短い間隔でタイマー設定できる関数もあります。
※EventSetMillisecondTimer関数についての詳細は↓の記事をご参照ください
手順2:OnTimer関数内に実行したい処理を記述する
void OnTimer() {
datetime serverTime = TimeCurrent(); // サーバーの現在時刻を取得
// サーバー時刻をコンソールに出力
Print("サーバーの現在時刻: ", TimeToString(serverTime, TIME_DATE|TIME_MINUTES));
}
続いてOnTimer関数の記述に移ります。
まずdateTime型のローカル変数「serverTime」に現在のサーバー時刻情報を代入します。
現在のサーバー時間情報を取得するにはTimeCurrent関数を使います。
※TimeCurrent関数についての詳細は↓の記事をご参照ください
最後にPrint関数を使い、特定のフォーマットにてローカル変数「serverTime」の値をエキスパートログに出力しています。
EventSetTimer関数で1秒ごとにタイマーイベントを生成するようOnInit関数内に記述していますから、1秒間隔でエキスパートログに指定したメッセージが出力されることになります。
Print関数の第2引数に記述されているTimeToString関数はdateTime型の情報を文字列型にタイプキャスト(型変換)する関数です。
※TimeToString関数についての詳細は↓の記事をご参照ください
※タイプキャストについての詳細は↓の記事をご参照ください
手順3:OnDeinit関数内にEventKillTimer関数を記述し、タイマーイベント削除設定をする。
// ファイルがチャートから削除される時に実行される関数
void OnDeinit(const int reason) {
EventKillTimer(); // タイマーを停止します
// チャートから削除されたことをユーザーに通知
if (reason == REASON_REMOVE) {
Comment("このエキスパートアドバイザーはチャートから削除されました。");
}
}
最後にOnDeinit関数内の記述を行います。OnDeinit関数は講座記事第7回で解説して以来、殆ど出番がありませんでしたが、MQL5 Program FileがMT5のチャート上から削除された際に、一度だけ処理を行う関数です。
OnDeinit関数内にはEventKillTimer関数という関数を記述します。EventKillTimer関数は引数もとらず、戻り値も返さないvoid型の関数なので記述するだけで処理を実行します。
EventKillTimer関数は呼び出したタイマーイベントを安全に停止させるための関数です。
OnDeinit関数が実行されるとき、すなわちMQL5 Program FileがMT5のチャート上から削除される際にタイマーが自動的に停止します。
もっとも、EventKillTimer関数が記述されていない場合、プログラムの操作の終了時に強制的に破壊されるようになっているのですが、プログラムが終了する際には、それまでに使用していたリソースを適切に解放することが一般的なプログラミングの慣習となっています。
よって、OnInit関数で設定したタイマーは、終了する際にOnDeinit関数で停止させる事によって不要なタイマーがシステム資源を消費し続けることを防ぎます。
※EventKillTimer関数についての詳細は↓の記事をご参照ください
その下の記述
if (reason == REASON_REMOVE)
についてですが、まずreasonという引数はOnDeinit関数で定義されている引数です。
OnDeinit(const int reason)
constという修飾子をつける事によって、値を定数化させています。
※constについての詳細は↓
MQL5 EA講座 第17回「定数(Constant)について」をご覧ください。
講座記事第7回でOnDeinit関数について解説した際には、初心者の方を混乱させてしまうと思い、あえて触れなかったのですが、この「reason」には「プログラムが終了した理由」を事前に定数化した値が格納される仕様になっています。
REASON_REMOVEというのは、その定数の1つでありプログラム終了の理由が「プログラムがチャートから削除された」場合に返ってくる定数となります。
つまり
if (reason == REASON_REMOVE) {
Comment("このエキスパートアドバイザーはチャートから削除されました。");
↑は「もしプログラム終了の理由が『プログラムがチャートから削除された』場合であればComment関数を使い、チャート上にコメント表示する」
と読み解けます。
※REASON_REMOVE以外にもreasonにはプログラム終了終了理由が格納されることがあります。
興味ある方は↓の「初期化解除の理由コード」に関する記事もご参照ください
まとめ
今回はOnTimer関数について解説しました。
OnTimer関数とは、任意に指定する「X秒」ごとに実行することができるイベントハンドラーです。
今後もEAの記述の大半はOnTick関数 に記述していくことに変わりはないでしょう。
その一方でOnTick関数は「価格の変動がなければ処理を実行しない」ので、価格の変動を待たずに実行させたい処理がある場合は定期的な間隔で処理を実行できるOnTimer関数を使うのは有効な選択肢と言えます。
OnTimer関数を使いこなせるようになる事でEA開発だけでなく、カスタムインジケ-タ開発にも応用が利くようになります。
ただし、OnTimer関数は単体で使える訳ではありません。
まず「どのくらいの間隔で処理を実行するか」という設定をOnInit関数内でおこないます。
「どのくらいの間隔で処理を実行するか」という具体的な設定にはEventSetTimer関数という関数を使います。
※詳細は当記事の「手順1:OnInit関数内にEventSetTimer関数を記述し、タイマーイベントを設定する。」セクションをご覧ください。
また、プログラムファイルをMT5のチャート上から削除する際に、タイマーイベントを停止させる処理も必要になります。
この処理は、OnDeinit関数内にはEventKillTimer関数という関数を記述する事によって実現します。
※詳細は当記事の「手順3:OnDeinit関数内にEventKillTimer関数を記述し、タイマーイベント削除設定をする。」セクションをご覧ください。
今回は以上とさせていただきます。
最後までお読みいただきありがとうございました。
<参照>
OnTick関数/OnStart関数/OnInit関数/OnDeinit関数/イベントハンドラー/EventSetTimer関数/EventSetMillisecondTimer関数/TimeCurrent関数/タイマーイベント/EventKillTimer関数/初期化解除の理由コード